Skip to content

Commit

Permalink
Change default upper bound from MAX to LEN
Browse files Browse the repository at this point in the history
  • Loading branch information
jongiddy committed Apr 15, 2024
1 parent 5aba155 commit 070fac5
Show file tree
Hide file tree
Showing 12 changed files with 133 additions and 99 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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: Tuple, B: Tuple>(
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]]))
}
```

Expand Down
83 changes: 48 additions & 35 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
};
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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,
Expand Down
64 changes: 31 additions & 33 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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: Tuple>(
//! 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)));
Expand All @@ -80,7 +77,7 @@
//! # use typle::typle;
//! #[typle(Tuple for 0..=12)]
//! pub fn sum<T: Tuple<u32>>(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);
Expand All @@ -106,11 +103,11 @@
//! fn multiply<S: Tuple, T: Tuple>(
//! s: S, // s: (S<0>,...)
//! t: T, // t: (T<0>,...)
//! ) -> typle_for!(i in ..T::LEN => <S<{i}> as Mul<T<{i}>>>::Output) // (<S<0> as Mul<T<0>>>::Output,...)
//! ) -> typle_for!(i in .. => <S<{i}> as Mul<T<{i}>>>::Output) // (<S<0> as Mul<T<0>>>::Output,...)
//! where
//! typle_bound!(i in ..T::LEN => S<{i}>): Mul<T<{i}>>, // S<0>: Mul<T<0>>,...
//! typle_bound!(i in .. => S<{i}>): Mul<T<{i}>>, // S<0>: Mul<T<0>>,...
//! {
//! 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!(
Expand All @@ -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<T> {
Expand Down Expand Up @@ -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<T<{ .. }>>`.
//! 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<T<{ ..T::MAX }>>`.
//! 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!`.
Expand Down Expand Up @@ -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<T<{i}>::State>
//! ),
//! }
Expand All @@ -226,8 +224,8 @@
//! {
//! // The state contains the output from all previous components and
//! // the state of the current component.
//! type State = TupleSequenceState<T<{ .. }>>;
//! type Output = typle_for!(i in ..T::LEN => <T<{i}> as Extract>::Output);
//! type State = TupleSequenceState<T<{ ..T::MAX }>>;
//! type Output = typle_for!(i in .. => <T<{i}> as Extract>::Output);
//!
//! fn extract(&self, state: Option<Self::State>) -> Self::Output {
//! // When LEN == 1 the code never changes `state`
Expand Down Expand Up @@ -552,7 +550,7 @@ impl TryFrom<TokenStream> for TypleMacro {
/// # use typle::typle;
/// #[typle(Tuple for 0..=12)]
/// fn all_long<T: Tuple<&str>>(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);
Expand All @@ -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: Tuple<&str>>(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);
Expand Down Expand Up @@ -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: Tuple<u32>>(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);
Expand Down Expand Up @@ -648,7 +646,7 @@ pub fn typle_any(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
/// }
///
/// #[typle(Tuple for 0..=12)]
/// impl<T: Tuple> CoalesceSome<T> for typle_for!(i in ..T::LEN => Option<T<{i}>>) {
/// impl<T: Tuple> CoalesceSome<T> for typle_for!(i in .. => Option<T<{i}>>) {
/// type Output = T;
///
/// fn coalesce_some(self) -> Option<Self::Output>
Expand Down Expand Up @@ -725,8 +723,8 @@ pub fn typle_fold(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
/// fn append<T: Tuple, A>(
/// 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));
Expand All @@ -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!(
Expand All @@ -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]] }},
/// )
/// }
///
Expand Down Expand Up @@ -812,9 +810,9 @@ pub fn typle_for(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
/// T: Tuple,
/// T<_>: Process<Output = u64>,
/// {
/// S = typle_variant!(i in .. => Option<T<{i}>::State>, [u64; i]),
/// U = typle_variant!{i in .. => u: [u32; i]},
/// V = typle_variant![..],
/// S = typle_variant!(i in ..T::MAX => Option<T<{i}>::State>, [u64; i]),
/// U = typle_variant!{i in ..Tuple::MAX => u: [u32; i]},
/// V = typle_variant![..Tuple::MAX],
/// Done([u64; Tuple::MAX]),
/// }
/// ```
Expand Down
6 changes: 3 additions & 3 deletions tests/compile/doc_typle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T<{i}>::State>
),
}
Expand All @@ -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<T<{ .. }>>;
type Output = typle_for!(i in ..T::LEN => <T<{i}> as Extract>::Output);
type State = TupleSequenceState<T<{ ..T::MAX }>>;
type Output = typle_for!(i in .. => <T<{i}> as Extract>::Output);

fn extract(&self, state: Option<Self::State>) -> Self::Output {
#[typle_attr_if(T::LEN == 1, allow(unused_mut))]
Expand Down
8 changes: 4 additions & 4 deletions tests/compile/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,20 @@ where
}

#[typle(Tuple for 0..=3)]
fn multiply<T, M>(t: T, m: M) -> typle_for!(i in ..T::LEN => <T<{i}> as Mul<M>>::Output)
fn multiply<T, M>(t: T, m: M) -> typle_for!(i in .. => <T<{i}> as Mul<M>>::Output)
where
T: Tuple,
T<_>: Mul<M>,
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<T: Tuple>(params: T) -> typle_for!(i in ..T::LEN => Box<T<{i}>>) {
typle_for!(i in ..T::LEN => Box::new(params[[i]]))
fn heapify<T: Tuple>(params: T) -> typle_for!(i in .. => Box<T<{i}>>) {
typle_for!(i in .. => Box::new(params[[i]]))
}

#[rustfmt::skip]
Expand Down
8 changes: 4 additions & 4 deletions tests/compile/method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ impl X {
}

pub fn associated<T: Tuple<u32>>(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<u32>>(&'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<u32>>(&'a self, t: T) -> T {
Expand All @@ -39,12 +39,12 @@ impl X {
pub fn inherent5<'a, T: Tuple<u32>>(&'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<u32>>(&'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)
}
}
Loading

0 comments on commit 070fac5

Please sign in to comment.