//! # Design //! #![cfg_attr(all(not(test), not(feature = "std")), no_std)] #![deny(elided_lifetimes_in_paths)] #![deny(unsafe_code)] #[cfg(feature = "alloc")] extern crate alloc; pub mod any; pub mod build; mod doc_macro; pub mod hkt; pub mod macros; pub mod mode; pub mod protocol; pub mod symbol; pub mod transform; pub mod walk; use core::ops::ControlFlow; use effectful::{short::ConvertShort, SendSync}; #[doc(inline)] pub use build::{Build, Builder}; #[doc(inline)] pub use walk::{Walk, Walker}; pub enum DefaultMode {} #[must_use] #[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone, SendSync)] pub enum Status { Ok, Err, } #[derive(Clone, Copy, PartialEq, Debug, SendSync)] #[must_use] pub enum Flow { Continue, Err, Done, } type Never = std::convert::Infallible; impl ConvertShort for Option { fn convert_short(short: Self) -> Flow { match short { None => Flow::Done, Some(_) => unreachable!(), } } } impl Flow { pub fn to_status(self) -> Status { match self { Flow::Continue | Flow::Done => Status::Ok, Flow::Err => Status::Err, } } pub fn to_done(self) -> Self { match self { Flow::Continue | Flow::Done => Flow::Done, Flow::Err => Flow::Err, } } pub fn to_continue(self) -> Self { match self { Flow::Continue | Flow::Done => Flow::Continue, Flow::Err => Flow::Err, } } pub fn to_control_flow(self) -> ControlFlow { match self { Flow::Continue => ControlFlow::Continue(()), flow => ControlFlow::Break(flow), } } } #[macro_export] macro_rules! Walk { { $(#[$($attr:tt)*])* $vis:vis struct $name:ident {$( $fvis:vis $field:ident: $type:ty ),* $(,)?} } => { const _: () = { impl<'ctx, M: 'ctx, E: effectful::environment::Environment> $crate::Walk<'ctx, M, E> for &'ctx $name where $name: effectful::bound::IsSync + effectful::environment::DynBind { type Walker = $crate::walkers::core::r#struct::StructWalker<'ctx, Info, $crate::any::StaticType, M, E>; fn into_walker<'e>(self) -> effectful::environment::NativeForm<'e, Self::Walker, E> { E::value($crate::walkers::core::r#struct::StructWalker::new(self)).cast() } } // impl<'ctx> $crate::WalkerTypes for &'ctx $name { // type Error = $crate::walkers::core::r#struct::StructWalkError>; // type Output = (); // } $vis enum Info {} #[allow(non_camel_case_types, unused)] enum FieldErrorKind<'ctx, M, E: effectful::environment::Environment> {$( $field($crate::walkers::core::key_value::KeyValueError<$crate::never::Never, <<&'ctx $type as $crate::Walk<'ctx, M, E>>::Walker as $crate::Walker<'ctx, E>>::Error>) ),*} #[allow(unused)] $vis struct FieldError<'ctx, M, E: effectful::environment::Environment>(FieldErrorKind<'ctx, M, E>); unsafe impl<'ctx, M, E: effectful::environment::Environment> effectful::bound::IsSend for FieldError<'ctx, M, E> {} unsafe impl<'ctx, M, E: effectful::environment::Environment> effectful::bound::IsSync for FieldError<'ctx, M, E> {} impl<'ctx, M, E: effectful::environment::Environment> ::core::fmt::Debug for FieldError<'ctx, M, E> { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { todo!() } } impl<'ctx, M: 'ctx, E: effectful::environment::Environment> $crate::walkers::core::r#struct::StructTypeInfo<'ctx, M, E> for Info where $name: effectful::bound::IsSync + effectful::environment::DynBind { const NAME: &'static str = stringify!($name); const FIELDS: &'static [&'static str] = &[$(stringify!($field)),*]; type FieldError = FieldError<'ctx, M, E>; type T = $name; type S = $crate::any::StaticType; #[allow(unreachable_code, non_snake_case, non_upper_case_globals, non_camel_case_types)] fn walk_field<'a>( index: usize, value: &'ctx Self::T, visitor: $crate::protocol::DynVisitor<'a, 'ctx, E>, ) -> effectful::environment::NativeForm<'a, Result<$crate::Flow, Self::FieldError>, E> { mod fields { enum Fields {$($field),*} $(pub const $field: usize = Fields::$field as usize;)* } match index { $(fields::$field => { let key_walker = $crate::walkers::core::value::ValueWalker::new(stringify!($field)); <&'ctx $type as $crate::Walk::<'ctx, M, E>>::into_walker(&value.$field) .then(|value_walker| { let walker = $crate::walkers::core::key_value::KeyValueWalker::<$crate::protocol::visitor::TagConst<{ $crate::TAG_FIELD.to_int() }>, _, _>::new($crate::protocol::visitor::TagConst, key_walker, value_walker); $crate::Walker::<'ctx, E>::walk(walker, visitor) }) .map(|result| match result { Ok(_) => { Ok($crate::Flow::Continue) } Err(err) => { Err(FieldError(FieldErrorKind::$field(err))) } }) // E::map($crate::Walker::<'ctx, E>::walk(walker, visitor), |result| match result { // Ok(_) => { // Ok($crate::Flow::Continue) // } // Err(err) => { // Err(FieldError(FieldErrorKind::$field(err))) // } // }) })* _ => E::ready(Ok($crate::Flow::Done)) } } } }; }; } // #[cfg(test)] // mod test { // use crate::effect::{BlockOn, Blocking, Spin}; // // use super::*; // use macro_rules_attribute::derive; // // #[derive(Walk!)] // struct Demo { // a: bool, // b: bool, // other: Other, // } // // #[derive(Walk!)] // struct Other { // value: bool, // } // // #[test] // fn demo() { // let value = Demo { // a: true, // b: false, // other: Other { value: true }, // }; // // let walker = Walk::::into_walker(&value); // let mut visitor = builders::debug::Visitor::::new(); // // dbg!(Spin::block_on(Walker::::walk( // walker, // &mut visitor // ))); // // todo!(); // } // } // pub mod demo { // use crate::{Build, BuildExt as _}; // use crate::{Walk, WalkExt as _}; // use macro_rules_attribute::derive; // // #[derive(Walk!)] // pub struct X { // pub a: bool, // pub b: bool, // } // // #[derive(Build!, PartialEq, Debug)] // pub struct Y { // pub b: bool, // pub a: bool, // } // // #[inline(never)] // pub fn ident(x: X) -> Y { // Y::build(x.as_walker()).unwrap() // // x.walk(Y::new_builder()).unwrap() // } // // #[test] // fn demo() { // assert_eq!(ident(X { a: true, b: false }), Y { a: true, b: false }); // // crate::effect::blocking::Spin::block_on(async { // let x = X { a: false, b: true }; // // let y = Y::build_async(x.as_async_walker().await).await.unwrap(); // // assert_eq!(y, Y { a: false, b: true }); // }); // // let x = X { a: false, b: true }; // // let y = Y::build(x.as_walker()).unwrap(); // // assert_eq!(y, Y { a: false, b: true }); // } // }