From 070fac53fdbb6f083fae81c44aecd89e6de0768c Mon Sep 17 00:00:00 2001 From: Jonathan Giddy Date: Mon, 15 Apr 2024 22:59:37 +0100 Subject: [PATCH] Change default upper bound from MAX to LEN --- README.md | 4 +- src/context.rs | 83 ++++++++++++++++++++--------------- src/lib.rs | 64 +++++++++++++-------------- tests/compile/doc_typle.rs | 6 +-- tests/compile/function.rs | 8 ++-- tests/compile/method.rs | 8 ++-- tests/compile/mod.expanded.rs | 19 ++++++++ tests/compile/pattern.rs | 4 +- tests/compile/typle_fold.rs | 8 +++- tests/expand/enum.rs | 6 +-- tests/expand/typle-for.rs | 12 ++--- tests/expand/where.rs | 10 ++--- 12 files changed, 133 insertions(+), 99 deletions(-) diff --git a/README.md b/README.md index 68f1e4c..ba9a4dd 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,9 @@ For example, to define a function to zip a pair of tuples into a tuple of pairs: pub fn zip( a: A, b: B, -) -> typle_for!(i in ..Tuple::LEN => (A<{i}>, B<{i}>)) +) -> typle_for!(i in .. => (A<{i}>, B<{i}>)) { - typle_for!(i in ..Tuple::LEN => (a[[i]], b[[i]])) + typle_for!(i in .. => (a[[i]], b[[i]])) } ``` diff --git a/src/context.rs b/src/context.rs index 13ec659..7544434 100644 --- a/src/context.rs +++ b/src/context.rs @@ -962,17 +962,21 @@ impl<'a> TypleContext<'a> { }) .transpose()? .unwrap_or(0); - let end = range - .end - .as_deref() - .map(|end| { - evaluate_usize(end).ok_or_else(|| { - Error::new(start.span(), "expected integer") - }) - }) - .transpose()? - .unwrap_or(self.typle_macro.max_len); - let end = match range.limits { + let end = match &range.end { + Some(expr) => match evaluate_usize(expr) { + Some(end) => end, + None => { + abort!(start, "expected integer"); + } + }, + None => match self.typle_len { + Some(end) => end, + None => { + abort!(range, "need an explicit end"); + } + }, + }; + let end = match range.limits { RangeLimits::HalfOpen(_) => end, RangeLimits::Closed(_) => end.saturating_add(1), }; @@ -1128,16 +1132,20 @@ impl<'a> TypleContext<'a> { }) .transpose()? .unwrap_or(0); - let end = range - .end - .as_deref() - .map(|end| { - evaluate_usize(end).ok_or_else(|| { - Error::new(end.span(), "expected integer") - }) - }) - .transpose()? - .unwrap_or(self.typle_macro.max_len); + let end = match &range.end { + Some(expr) => match evaluate_usize(expr) { + Some(end) => end, + None => { + abort!(range.end, "expected integer"); + } + }, + None => match self.typle_len { + Some(end) => end, + None => { + abort!(range.end, "need an explicit range end"); + } + }, + }; let end = match range.limits { RangeLimits::HalfOpen(_) => end, RangeLimits::Closed(_) => end.saturating_add(1), @@ -2273,26 +2281,31 @@ impl<'a> TypleContext<'a> { }) .transpose()? .unwrap_or(0); - let end = range - .end - .as_ref() - .map(|expr| { - evaluate_usize(expr).ok_or_else(|| { + let end = match &range.end { + Some(expr) => match evaluate_usize(expr) { + Some(end) => end, + None => { if let Some(suspicious_ident) = &state.suspicious_ident { - Error::new( - suspicious_ident.span(), + abort!( + suspicious_ident, format!( "range end invalid, possibly missing `{}: {}` bound", suspicious_ident, self.typle_macro.ident - ), - ) + ) + ); } else { - Error::new(range.end.span(), "range end invalid") + abort!(range.end, "range end invalid"); } - }) - }) - .transpose()? - .unwrap_or(self.typle_macro.max_len) + } + }, + None => match self.typle_len { + Some(end) => end, + None => { + abort!(range, "need an explicit end in range"); + } + }, + }; + let end = end .checked_add(match range.limits { RangeLimits::HalfOpen(_) => 0, RangeLimits::Closed(_) => 1, diff --git a/src/lib.rs b/src/lib.rs index d43daca..287287d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,18 +55,15 @@ //! the macro the typle index variable can provide access to each component of //! an existing tuple type or expression. //! -//! The associated constant `LEN` provides the length of the tuple in each -//! generated item. This value can be used in typle index expressions. -//! //! ```rust //! # use typle::typle; //! // Split off the first component //! #[typle(Tuple for 1..=12)] //! fn split( //! t: T // t: (T<0>, T<1>, T<2>,...) -//! ) -> (T<0>, typle_for!(i in 1..T::LEN => T<{i}>)) // (T<0>, (T<1>, T<2>,...)) +//! ) -> (T<0>, typle_for!(i in 1.. => T<{i}>)) // (T<0>, (T<1>, T<2>,...)) //! { -//! (t[[0]], typle_for!(i in 1..T::LEN => t[[i]])) // (t.0, (t.1, t.2,...)) +//! (t[[0]], typle_for!(i in 1.. => t[[i]])) // (t.0, (t.1, t.2,...)) //! } //! //! assert_eq!(split(('1', 2, 3.0)), ('1', (2, 3.0))); @@ -80,7 +77,7 @@ //! # use typle::typle; //! #[typle(Tuple for 0..=12)] //! pub fn sum>(t: T) -> u32 { -//! typle_fold!(0; i in ..T::LEN => |total| total + t[[i]]) +//! typle_fold!(0; i in .. => |total| total + t[[i]]) //! } //! assert_eq!(sum(()), 0); //! assert_eq!(sum((1, 4, 9, 16)), 30); @@ -106,11 +103,11 @@ //! fn multiply( //! s: S, // s: (S<0>,...) //! t: T, // t: (T<0>,...) -//! ) -> typle_for!(i in ..T::LEN => as Mul>>::Output) // ( as Mul>>::Output,...) +//! ) -> typle_for!(i in .. => as Mul>>::Output) // ( as Mul>>::Output,...) //! where -//! typle_bound!(i in ..T::LEN => S<{i}>): Mul>, // S<0>: Mul>,... +//! typle_bound!(i in .. => S<{i}>): Mul>, // S<0>: Mul>,... //! { -//! typle_for!(i in ..T::LEN => s[[i]] * t[[i]]) // (s.0 * t.0,...) +//! typle_for!(i in .. => s[[i]] * t[[i]]) // (s.0 * t.0,...) //! } //! //! assert_eq!( @@ -122,6 +119,9 @@ //! Use the `typle_index!` macro in a `for` loop to iterate over a range bounded //! by typle index expressions. //! +//! The associated constant `LEN` provides the length of the tuple in each +//! generated item. This value can be used in typle index expressions. +//! //! ```rust //! # use typle::typle; //! # struct MyStruct { @@ -157,13 +157,11 @@ //! demonstrates the use of `typle` with `enum`s. //! //! Typled `enum`s are implemented for the maximum length. When referring to -//! these types from other typled items, use `TupleSequenceState>`. -//! For typle range expressions the default lower bound is 0 and the default -//! upper bound is `T::MAX`, the maximum length for the tuple. This will fill in -//! unused type parameters with the `never` type provided for the `typle` macro. -//! The default type is [`!`] but this is not available in stable Rust. -//! [`std::convert::Infallible`] is an uninhabited type that is available in -//! stable Rust but any type is permissible. +//! these types from other typled items, use `TupleSequenceState>`. +//! This will fill in unused type parameters with the `never` type provided for +//! the `typle` macro. The default type is [`!`] but this is not available in +//! stable Rust. [`std::convert::Infallible`] is an uninhabited type that is +//! available in stable Rust but any type is permissible. //! //! The [`typle_variant!`] macro creates multiple enum variants by looping //! similarly to `typle_for!`. @@ -210,7 +208,7 @@ //! T: Tuple, //! T<_>: Extract, //! { -//! S = typle_variant!(i in .. => +//! S = typle_variant!(i in ..T::MAX => //! typle_for!(j in ..i => T::<{j}>::Output), Option::State> //! ), //! } @@ -226,8 +224,8 @@ //! { //! // The state contains the output from all previous components and //! // the state of the current component. -//! type State = TupleSequenceState>; -//! type Output = typle_for!(i in ..T::LEN => as Extract>::Output); +//! type State = TupleSequenceState>; +//! type Output = typle_for!(i in .. => as Extract>::Output); //! //! fn extract(&self, state: Option) -> Self::Output { //! // When LEN == 1 the code never changes `state` @@ -552,7 +550,7 @@ impl TryFrom for TypleMacro { /// # use typle::typle; /// #[typle(Tuple for 0..=12)] /// fn all_long>(t: T) -> bool { -/// typle_all!(i in ..T::LEN => t[[i]].len() > 5) +/// typle_all!(i in .. => t[[i]].len() > 5) /// } /// // Return `true` if all words meet the criteria. /// assert_eq!(all_long(("longest", "phrase")), true); @@ -578,7 +576,7 @@ pub fn typle_all(item: proc_macro::TokenStream) -> proc_macro::TokenStream { /// # use typle::typle; /// #[typle(Tuple for 0..=12)] /// fn any_long>(t: T) -> bool { -/// typle_any!(i in ..T::LEN => t[[i]].len() > 5) +/// typle_any!(i in .. => t[[i]].len() > 5) /// } /// // Return `true` if any word meets the criteria. /// assert_eq!(any_long(("the", "longest", "word")), true); @@ -610,7 +608,7 @@ pub fn typle_any(item: proc_macro::TokenStream) -> proc_macro::TokenStream { /// # use typle::typle; /// #[typle(Tuple for 0..=12)] /// pub fn sum>(t: T) -> u32 { -/// typle_fold!(0; i in ..T::LEN => |total| total + t[[i]]) +/// typle_fold!(0; i in .. => |total| total + t[[i]]) /// } /// // An empty tuple uses the initial value. /// assert_eq!(sum(()), 0); @@ -648,7 +646,7 @@ pub fn typle_any(item: proc_macro::TokenStream) -> proc_macro::TokenStream { /// } /// /// #[typle(Tuple for 0..=12)] -/// impl CoalesceSome for typle_for!(i in ..T::LEN => Option>) { +/// impl CoalesceSome for typle_for!(i in .. => Option>) { /// type Output = T; /// /// fn coalesce_some(self) -> Option @@ -725,8 +723,8 @@ pub fn typle_fold(item: proc_macro::TokenStream) -> proc_macro::TokenStream { /// fn append( /// t: T, /// a: A, -/// ) -> typle_for!{i in 0..=T::LEN => if i < T::LEN { typle_ty!(T<{i}>) } else { A }} { -/// typle_for!{i in 0..=T::LEN => if i < T::LEN { t[[i]] } else { a }} +/// ) -> typle_for!{i in ..=T::LEN => if i < T::LEN { typle_ty!(T<{i}>) } else { A }} { +/// typle_for!{i in ..=T::LEN => if i < T::LEN { t[[i]] } else { a }} /// } /// /// assert_eq!(append((1, 2, 3), 4), (1, 2, 3, 4)); @@ -742,7 +740,7 @@ pub fn typle_fold(item: proc_macro::TokenStream) -> proc_macro::TokenStream { /// T: Tuple, /// T<_>: ToString, /// { -/// typle_for![i in ..T::LEN => t[[i]].to_string()] +/// typle_for![i in .. => t[[i]].to_string()] /// } /// /// assert_eq!( @@ -760,13 +758,13 @@ pub fn typle_fold(item: proc_macro::TokenStream) -> proc_macro::TokenStream { /// t: T /// ) -> ( /// // (T<0>, T<2>,...) -/// typle_for!{i in ..T::LEN => if i % 2 == 0 { typle_ty!(T<{i}>) }}, +/// typle_for!{i in .. => if i % 2 == 0 { typle_ty!(T<{i}>) }}, /// // (T<1>, T<3>,...) -/// typle_for!{i in ..T::LEN => if i % 2 == 1 { typle_ty!(T<{i}>) }}, +/// typle_for!{i in .. => if i % 2 == 1 { typle_ty!(T<{i}>) }}, /// ) { /// ( -/// typle_for!{i in ..T::LEN => if i % 2 == 0 { t[[i]] }}, -/// typle_for!{i in ..T::LEN => if i % 2 == 1 { t[[i]] }}, +/// typle_for!{i in .. => if i % 2 == 0 { t[[i]] }}, +/// typle_for!{i in .. => if i % 2 == 1 { t[[i]] }}, /// ) /// } /// @@ -812,9 +810,9 @@ pub fn typle_for(item: proc_macro::TokenStream) -> proc_macro::TokenStream { /// T: Tuple, /// T<_>: Process, /// { -/// S = typle_variant!(i in .. => Option::State>, [u64; i]), -/// U = typle_variant!{i in .. => u: [u32; i]}, -/// V = typle_variant![..], +/// S = typle_variant!(i in ..T::MAX => Option::State>, [u64; i]), +/// U = typle_variant!{i in ..Tuple::MAX => u: [u32; i]}, +/// V = typle_variant![..Tuple::MAX], /// Done([u64; Tuple::MAX]), /// } /// ``` diff --git a/tests/compile/doc_typle.rs b/tests/compile/doc_typle.rs index ae270af..8477a84 100644 --- a/tests/compile/doc_typle.rs +++ b/tests/compile/doc_typle.rs @@ -40,7 +40,7 @@ mod tuple { T: Tuple, T<_>: Extract, { - S = typle_variant!(i in .. => + S = typle_variant!(i in ..T::MAX => typle_for!(j in ..i => T::<{j}>::Output), Option::State> ), } @@ -56,8 +56,8 @@ mod tuple { { // The state contains the output from all previous components and the state // of the current component. - type State = TupleSequenceState>; - type Output = typle_for!(i in ..T::LEN => as Extract>::Output); + type State = TupleSequenceState>; + type Output = typle_for!(i in .. => as Extract>::Output); fn extract(&self, state: Option) -> Self::Output { #[typle_attr_if(T::LEN == 1, allow(unused_mut))] diff --git a/tests/compile/function.rs b/tests/compile/function.rs index 51a8942..9eed351 100644 --- a/tests/compile/function.rs +++ b/tests/compile/function.rs @@ -17,20 +17,20 @@ where } #[typle(Tuple for 0..=3)] -fn multiply(t: T, m: M) -> typle_for!(i in ..T::LEN => as Mul>::Output) +fn multiply(t: T, m: M) -> typle_for!(i in .. => as Mul>::Output) where T: Tuple, T<_>: Mul, M: Copy, { - typle_for!(i in ..T::LEN => t[[i]] * m) + typle_for!(i in .. => t[[i]] * m) } // `heapify` and `zip` as described at // https://gist.github.com/soqb/9ce3d4502cc16957b80c388c390baafc#syntax-for-type-transformations #[typle(Tuple for 0..=3)] -fn heapify(params: T) -> typle_for!(i in ..T::LEN => Box>) { - typle_for!(i in ..T::LEN => Box::new(params[[i]])) +fn heapify(params: T) -> typle_for!(i in .. => Box>) { + typle_for!(i in .. => Box::new(params[[i]])) } #[rustfmt::skip] diff --git a/tests/compile/method.rs b/tests/compile/method.rs index 2306e23..2b68acc 100644 --- a/tests/compile/method.rs +++ b/tests/compile/method.rs @@ -13,11 +13,11 @@ impl X { } pub fn associated>(t: T, i: u32) -> T { - typle_for!(j in ..T::LEN => t[[j]] + i) + typle_for!(j in .. => t[[j]] + i) } pub fn inherent1<'a, T: Tuple>(&'a self, t: T) -> T { - typle_for!(j in ..T::LEN => t[[j]] + self.i) + typle_for!(j in .. => t[[j]] + self.i) } pub fn inherent2<'a, T: Tuple>(&'a self, t: T) -> T { @@ -39,12 +39,12 @@ impl X { pub fn inherent5<'a, T: Tuple>(&'a self, t: T) -> T { #[typle_attr_if(T::LEN == 0, allow(unused_variables))] let X { i } = self; - typle_for!(j in ..T::LEN => t[[j]] + i) + typle_for!(j in .. => t[[j]] + i) } pub fn inherent6<'a, T: Tuple>(&'a self, t: T) -> T { #[typle_attr_if(T::LEN == 0, allow(unused_variables))] let Self { i } = self; - typle_for!(j in ..T::LEN => t[[j]] + i) + typle_for!(j in .. => t[[j]] + i) } } diff --git a/tests/compile/mod.expanded.rs b/tests/compile/mod.expanded.rs index fa6fd59..1d36c36 100644 --- a/tests/compile/mod.expanded.rs +++ b/tests/compile/mod.expanded.rs @@ -2045,12 +2045,18 @@ pub mod typle_fold { } pub trait UsefulTrait { type UsefulType: IsUseful; + const SIZE: usize; } impl UsefulTrait for (T0,) where T0: UsefulTrait, { type UsefulType = T0::UsefulType; + const SIZE: usize = loop { + let total = 0; + let total = total + ::SIZE; + break total; + }; } impl UsefulTrait for (T0, T1) where @@ -2059,6 +2065,12 @@ pub mod typle_fold { ::UsefulType: IsUseful, { type UsefulType = <::UsefulType as IsUseful>::State; + const SIZE: usize = loop { + let total = 0; + let total = total + ::SIZE; + let total = total + ::SIZE; + break total; + }; } impl UsefulTrait for (T0, T1, T2) where @@ -2073,5 +2085,12 @@ pub mod typle_fold { type UsefulType = <::UsefulType as IsUseful< <::UsefulType as IsUseful>::State, >>::State; + const SIZE: usize = loop { + let total = 0; + let total = total + ::SIZE; + let total = total + ::SIZE; + let total = total + ::SIZE; + break total; + }; } } diff --git a/tests/compile/pattern.rs b/tests/compile/pattern.rs index d2c7def..bccc13a 100644 --- a/tests/compile/pattern.rs +++ b/tests/compile/pattern.rs @@ -32,7 +32,7 @@ impl> MyStruct { #[typle(Tuple for 1..=12)] fn multiply_by>(t: T, m: u32) -> T { // let (x0, x1, x2) = (t.0 * m, t.1 * m, t.2 * m); - let typle_for!(i in ..T::LEN => x::) = typle_for!(i in ..T::LEN => t[[i]] * m); + let typle_for!(i in .. => x::) = typle_for!(i in .. => t[[i]] * m); assert_eq!(x0, t.0 * m); - typle_for!(i in ..T::LEN => x::) + typle_for!(i in .. => x::) } diff --git a/tests/compile/typle_fold.rs b/tests/compile/typle_fold.rs index 8999f24..9b67118 100644 --- a/tests/compile/typle_fold.rs +++ b/tests/compile/typle_fold.rs @@ -8,13 +8,15 @@ pub trait IsUseful { pub trait UsefulTrait { type UsefulType: IsUseful; + + const SIZE: usize; } #[typle(Tuple for 1..=3)] impl UsefulTrait for T where T<_>: UsefulTrait, - typle_bound!(i in 1..T::LEN => T<{i}>::UsefulType):IsUseful< + typle_bound!(i in 1.. => T<{i}>::UsefulType): IsUseful< typle_fold!( T0::UsefulType; j in 1..i => |Inner| ::UsefulType as IsUseful>::State @@ -23,6 +25,8 @@ where { type UsefulType = typle_fold!( T0::UsefulType; - j in 1..T::LEN => |Inner| ::UsefulType as IsUseful>::State + j in 1.. => |Inner| ::UsefulType as IsUseful>::State ); + + const SIZE: usize = typle_fold!(0; i in .. => |total| total + T::<{i}>::SIZE); } diff --git a/tests/expand/enum.rs b/tests/expand/enum.rs index a52058d..4449549 100644 --- a/tests/expand/enum.rs +++ b/tests/expand/enum.rs @@ -15,11 +15,11 @@ where { // `typle_variant!` creates a variant for each component. The variant will have a number // added to the variant name here. `S2(Option, [u64; 2])` - S = typle_variant!(i in .. => Option::State>, [u64; i]), + S = typle_variant!(i in ..T::MAX => Option::State>, [u64; i]), // U2 {u: [u32; 2]} - U = typle_variant! {i in .. => u: [u32; i]}, + U = typle_variant! {i in ..Tuple::MAX => u: [u32; i]}, // V2 - V = typle_variant![..], + V = typle_variant![..Tuple::MAX], Done([u64; Tuple::MAX]), } diff --git a/tests/expand/typle-for.rs b/tests/expand/typle-for.rs index 8c5c9fa..e3de41f 100644 --- a/tests/expand/typle-for.rs +++ b/tests/expand/typle-for.rs @@ -10,19 +10,19 @@ impl S where T: Tuple, { - fn new(t: typle_for!(i in ..T::LEN => &T<{i}>)) { + fn new(t: typle_for!(i in .. => &T<{i}>)) { // Square brackets create an array - let a: [u32; T::LEN] = typle_for![i in 0..T::LEN => *t[[i]] * 2]; + let a: [u32; T::LEN] = typle_for![i in .. => *t[[i]] * 2]; // Parentheses create a tuple // The default bounds of the range are 0..Tuple::LEN - let b = typle_for!(i in ..T::LEN => *t[[i]] * 2); + let b = typle_for!(i in .. => *t[[i]] * 2); // Arbitrary expressions can be used for the indices and // the iterator variable can be left out if not needed let init: [Option; T::LEN] = typle_for![T::LEN * 2..T::LEN * 3 => None]; // const-if can be used to filter components in `typle_for!`. Braces // always use const-if. - let c = typle_for!(i in ..T::LEN => if typle_const!(i == 0) {b[[i]]}); - let d = typle_for!{i in ..T::LEN => if i == 0 {b[[i]]}}; - let e = typle_for![i in ..T::LEN => if typle_const!(i == 0) {b[[i]]}]; + let c = typle_for!(i in .. => if typle_const!(i == 0) {b[[i]]}); + let d = typle_for!{i in .. => if i == 0 {b[[i]]}}; + let e = typle_for![i in .. => if typle_const!(i == 0) {b[[i]]}]; } } diff --git a/tests/expand/where.rs b/tests/expand/where.rs index 9ce978a..473a794 100644 --- a/tests/expand/where.rs +++ b/tests/expand/where.rs @@ -21,7 +21,7 @@ where impl Extract for TupleC where S: Debug + Tuple, - S<{ 1..S::LEN }>: Extract, + S<{ 1.. }>: Extract, T: Tuple, T<0>: Extract>, T: Debug, @@ -30,16 +30,16 @@ where // typle_bound! allows the component index to be used in the trait bound #[typle(Tuple for 1..=2)] -impl TraitD for TupleD> +impl TraitD for TupleD> where T: Tuple, - typle_bound!(i in ..T::LEN => T<{i}>): Mul>, + typle_bound!(i in .. => T<{i}>): Mul>, T<{ T::LEN - 1 }>: AsRef, F: Fn(T) -> T, { fn g() { - // T{ .. } expands to all types in a referenced enum - let f: TupleD> = TupleD::>::new(); + // T{ ..T::MAX } expands to all types in a referenced enum + let f: TupleD> = TupleD::>::new(); T::<0>::output_to_bytestream(); } }