Skip to content

Commit

Permalink
Support type ranges in more places
Browse files Browse the repository at this point in the history
  • Loading branch information
jongiddy committed May 6, 2024
1 parent 98f5a57 commit 5f2464f
Show file tree
Hide file tree
Showing 6 changed files with 337 additions and 6 deletions.
140 changes: 134 additions & 6 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use syn::{
use zip_clone::ZipClone as _;

use crate::constant::{evaluate_bool, evaluate_range, evaluate_usize};
use crate::iterator::ListIterator4;
use crate::syn_ext::GeneralFunction;
use crate::TypleMacro;

Expand Down Expand Up @@ -2538,9 +2539,10 @@ impl<'a> TypleContext<'a> {
}
}
PathArguments::Parenthesized(args) => {
for input in &mut args.inputs {
self.replace_type(input)?;
}
args.inputs = std::mem::take(&mut args.inputs)
.into_iter()
.flat_map(|ty| self.replace_type_in_list(ty))
.collect::<Result<_>>()?;
if let ReturnType::Type(_, ty) = &mut args.output {
self.replace_type(ty)?;
}
Expand Down Expand Up @@ -2576,9 +2578,18 @@ impl<'a> TypleContext<'a> {
self.replace_expr(&mut array.len, &mut state)?;
}
Type::BareFn(bare_fn) => {
for arg in &mut bare_fn.inputs {
self.replace_type(&mut arg.ty)?;
}
bare_fn.inputs = std::mem::take(&mut bare_fn.inputs)
.into_iter()
.flat_map(|arg| {
self.replace_type_in_list(arg.ty).map(move |res| {
res.map(|ty| syn::BareFnArg {
attrs: arg.attrs.clone(),
name: arg.name.clone(),
ty,
})
})
})
.collect::<Result<_>>()?;
if let ReturnType::Type(_, ty) = &mut bare_fn.output {
self.replace_type(ty)?;
}
Expand Down Expand Up @@ -2623,6 +2634,123 @@ impl<'a> TypleContext<'a> {
Ok(())
}

fn replace_type_in_list(&'a self, mut ty: Type) -> impl Iterator<Item = Result<Type>> + 'a {
match &mut ty {
Type::Macro(syn::TypeMacro { mac }) => {
if let Some(ident) = mac.path.get_ident() {
if ident == "typle_args" {
let token_stream = std::mem::take(&mut mac.tokens);
let default_span = token_stream.span();
let mut tokens = token_stream.into_iter();
let (pattern, range) =
match self.parse_pattern_range(&mut tokens, default_span) {
Ok(t) => t,
Err(e) => return ListIterator4::Variant0(std::iter::once(Err(e))),
};
if range.is_empty() {
return ListIterator4::Variant3(std::iter::empty());
}
let token_stream = tokens.collect::<TokenStream>();
let ty = match syn::parse2::<Type>(token_stream) {
Ok(ty) => ty,
Err(e) => return ListIterator4::Variant0(std::iter::once(Err(e))),
};
let mut context = self.clone();
if let Some(ident) = pattern.clone() {
context.constants.insert(ident, 0);
}
return ListIterator4::Variant2(range.zip_clone(ty).map({
move |(index, mut ty)| {
if let Some(ident) = &pattern {
*context.constants.get_mut(ident).unwrap() = index;
}
match context.replace_type(&mut ty) {
Ok(()) => Ok(ty),
Err(e) => Err(e),
}
}
}));
}
}
}
Type::Path(syn::TypePath { qself, path })
if qself.is_none() && path.leading_colon.is_none() =>
{
let mut segments = path.segments.iter_mut();
if let Some(first) = segments.next() {
if let (Some(typle), PathArguments::AngleBracketed(arguments), None) = (
self.typles.get(&first.ident),
&mut first.arguments,
segments.next(),
) {
let mut iter = arguments.args.iter_mut().fuse();
if let (Some(GenericArgument::Const(ref mut expr)), None) =
(iter.next(), iter.next())
{
let mut state = BlockState::default();
match self.replace_expr(expr, &mut state) {
Ok(_) => {}
Err(e) => return ListIterator4::Variant0(std::iter::once(Err(e))),
}
if let Some(range) = evaluate_range(expr) {
// T<{..}>
let start = match range
.start
.as_deref()
.map(|start| {
evaluate_usize(start).ok_or_else(|| {
Error::new(start.span(), "expected integer")
})
})
.transpose()
{
Ok(start) => start.unwrap_or(0),
Err(e) => {
return ListIterator4::Variant0(std::iter::once(Err(e)))
}
};
let end = match &range.end {
Some(expr) => match evaluate_usize(expr) {
Some(end) => end,
None => {
return ListIterator4::Variant0(std::iter::once(Err(
Error::new(range.end.span(), "expected integer"),
)));
}
},
None => match self.typle_len {
Some(end) => end,
None => {
return ListIterator4::Variant0(std::iter::once(Err(
Error::new(
range.end.span(),
"need an explicit range end",
),
)));
}
},
};
let end = match range.limits {
RangeLimits::HalfOpen(_) => end,
RangeLimits::Closed(_) => end.saturating_add(1),
};
return ListIterator4::Variant1((start..end).map({
let span = path.span();
move |i| self.get_type(typle, i, span)
}));
}
}
}
}
}
_ => {}
}
match self.replace_type(&mut ty) {
Ok(()) => ListIterator4::Variant0(std::iter::once(Ok(ty))),
Err(e) => ListIterator4::Variant0(std::iter::once(Err(e))),
}
}

// Return Some(usize) if the angled bracketed generic arguments is a `typle_ident!` macro.
fn typle_ident(&self, args: &mut syn::AngleBracketedGenericArguments) -> Result<Option<usize>> {
if args.args.len() == 1 {
Expand Down
25 changes: 25 additions & 0 deletions src/iterator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
pub enum ListIterator4<I0, I1, I2, I3> {
Variant0(I0),
Variant1(I1),
Variant2(I2),
Variant3(I3),
}

impl<I0, I1, I2, I3> Iterator for ListIterator4<I0, I1, I2, I3>
where
I0: Iterator,
I1: Iterator<Item = I0::Item>,
I2: Iterator<Item = I0::Item>,
I3: Iterator<Item = I0::Item>,
{
type Item = I0::Item;

fn next(&mut self) -> Option<Self::Item> {
match self {
ListIterator4::Variant0(iter) => iter.next(),
ListIterator4::Variant1(iter) => iter.next(),
ListIterator4::Variant2(iter) => iter.next(),
ListIterator4::Variant3(iter) => iter.next(),
}
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,7 @@

mod constant;
mod context;
mod iterator;
mod syn_ext;

use constant::evaluate_usize;
Expand Down
127 changes: 127 additions & 0 deletions tests/compile/mod.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2032,6 +2032,133 @@ pub mod type_alias {
T2: Process,
= (Option<<T0>::Output>, Option<<T1>::Output>, Option<<T2>::Output>);
}
pub mod typle_args {
#![allow(unused)]
use typle::typle;
struct World {}
trait ExclusiveSystemParam {}
struct ExclusiveSystemParamItem<F> {
f: F,
}
trait ExclusiveSystemParamFunction<F> {
type In;
type Out;
type Param;
fn run(
&mut self,
world: &mut World,
_in: Self::In,
param_value: ExclusiveSystemParamItem<Self::Param>,
) -> Self::Out;
}
struct Func {}
impl<Out, Func: Send + Sync + 'static> ExclusiveSystemParamFunction<fn() -> Out>
for Func
where
for<'a> &'a mut Func: FnMut(&mut World) -> Out + FnMut(&mut World) -> Out,
Out: 'static,
{
type In = ();
type Out = Out;
type Param = ();
#[inline]
fn run(
&mut self,
world: &mut World,
_in: (),
param_value: ExclusiveSystemParamItem<()>,
) -> Self::Out {
::core::panicking::panic("not yet implemented")
}
}
impl<
Out,
Func: Send + Sync + 'static,
F0,
> ExclusiveSystemParamFunction<fn(F0) -> Out> for Func
where
for<'a> &'a mut Func: FnMut(&mut World, F0) -> Out
+ FnMut(&mut World, ExclusiveSystemParamItem<F0>) -> Out,
Out: 'static,
F0: ExclusiveSystemParam,
{
type In = ();
type Out = Out;
type Param = (F0,);
#[inline]
fn run(
&mut self,
world: &mut World,
_in: (),
param_value: ExclusiveSystemParamItem<(F0,)>,
) -> Self::Out {
::core::panicking::panic("not yet implemented")
}
}
impl<
Out,
Func: Send + Sync + 'static,
F0,
F1,
> ExclusiveSystemParamFunction<fn(F0, F1) -> Out> for Func
where
for<'a> &'a mut Func: FnMut(&mut World, F0, F1) -> Out
+ FnMut(
&mut World,
ExclusiveSystemParamItem<F0>,
ExclusiveSystemParamItem<F1>,
) -> Out,
Out: 'static,
F0: ExclusiveSystemParam,
F1: ExclusiveSystemParam,
{
type In = ();
type Out = Out;
type Param = (F0, F1);
#[inline]
fn run(
&mut self,
world: &mut World,
_in: (),
param_value: ExclusiveSystemParamItem<(F0, F1)>,
) -> Self::Out {
::core::panicking::panic("not yet implemented")
}
}
impl<
Out,
Func: Send + Sync + 'static,
F0,
F1,
F2,
> ExclusiveSystemParamFunction<fn(F0, F1, F2) -> Out> for Func
where
for<'a> &'a mut Func: FnMut(&mut World, F0, F1, F2) -> Out
+ FnMut(
&mut World,
ExclusiveSystemParamItem<F0>,
ExclusiveSystemParamItem<F1>,
ExclusiveSystemParamItem<F2>,
) -> Out,
Out: 'static,
F0: ExclusiveSystemParam,
F1: ExclusiveSystemParam,
F2: ExclusiveSystemParam,
{
type In = ();
type Out = Out;
type Param = (F0, F1, F2);
#[inline]
fn run(
&mut self,
world: &mut World,
_in: (),
param_value: ExclusiveSystemParamItem<(F0, F1, F2)>,
) -> Self::Out {
::core::panicking::panic("not yet implemented")
}
}
}
pub mod typle_fold {
use typle::typle;
pub struct Something {}
Expand Down
1 change: 1 addition & 0 deletions tests/compile/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ pub mod macros;
pub mod method;
pub mod pattern;
pub mod type_alias;
pub mod typle_args;
pub mod typle_fold;
pub mod unzip;
49 changes: 49 additions & 0 deletions tests/compile/typle_args.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#![allow(unused)]
use typle::typle;

struct World {}

trait ExclusiveSystemParam {}

struct ExclusiveSystemParamItem<F> {
f: F,
}

trait ExclusiveSystemParamFunction<F> {
type In;
type Out;
type Param;

fn run(
&mut self,
world: &mut World,
_in: Self::In,
param_value: ExclusiveSystemParamItem<Self::Param>,
) -> Self::Out;
}

struct Func {}

// https://github.com/jongiddy/bevy/blob/ac91b191/crates/bevy_ecs/src/system/exclusive_function_system.rs#L183
#[typle(Tuple for 0..=3)]
impl<Out, Func: Send + Sync + 'static, F: Tuple> ExclusiveSystemParamFunction<fn(F<{ .. }>) -> Out>
for Func
where
for<'a> &'a mut Func: FnMut(&mut World, F<{ .. }>) -> Out
+ FnMut(&mut World, typle_args!(i in .. => ExclusiveSystemParamItem<F<{i}>>)) -> Out,
Out: 'static,
F<_>: ExclusiveSystemParam,
{
type In = ();
type Out = Out;
type Param = F;
#[inline]
fn run(
&mut self,
world: &mut World,
_in: (),
param_value: ExclusiveSystemParamItem<F>,
) -> Self::Out {
todo!()
}
}

0 comments on commit 5f2464f

Please sign in to comment.