//! # Design
//!
#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
#![deny(elided_lifetimes_in_paths)]
#[cfg(feature = "alloc")]
extern crate alloc;
pub mod any;
mod build;
pub mod effect;
pub mod hkt;
pub mod macros;
pub mod protocol;
pub mod symbol;
mod transform;
mod walk;
use core::ops::ControlFlow;
pub use build::*;
use effect::ConvertShort;
pub use transform::*;
pub use walk::*;
use symbol::Symbol;
pub mod never {
mod sealed {
pub trait Extract {
type Never;
}
impl<T> Extract for fn() -> T {
type Never = T;
}
}
/// Test
pub type Never = <fn() -> ! as sealed::Extract>::Never;
}
pub const TAG_TYPE_NAME: Symbol = Symbol::new("Type Name");
pub const TAG_TYPE_ID: Symbol = Symbol::new("Type ID");
pub const TAG_TYPE_SIZE: Symbol = Symbol::new("Type Size");
pub const TAG_FIELD_NAMES: Symbol = Symbol::new("Field Names");
pub const TAG_KEY: Symbol = Symbol::new("Key");
pub const TAG_VALUE: Symbol = Symbol::new("Value");
pub const TAG_SEQ_INDEX: Symbol = Symbol::new("Seq Index");
pub const TAG_SEQ_LEN: Symbol = Symbol::new("Seq Length");
pub const TAG_STRUCT: Symbol = Symbol::new("Struct");
pub const TAG_MAP: Symbol = Symbol::new("Map");
pub const TAG_SEQ: Symbol = Symbol::new("Sequence");
pub const TAG_FIELD: Symbol = Symbol::new("Field");
pub const TAG_KEY_VALUE: Symbol = Symbol::new("Key Value");
pub const TAG_ENUM: Symbol = Symbol::new("Enum");
pub enum DefaultMode {}
#[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum Status {
Ok,
Err,
}
#[derive(Clone, Copy, PartialEq, Debug)]
#[must_use]
pub enum Flow {
Continue,
Err,
Done,
}
impl ConvertShort<ControlFlow<Flow>> for Option<never::Never> {
fn convert_short(short: Self) -> ControlFlow<Flow> {
match short {
None => ControlFlow::Break(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<Self> {
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: $crate::effect::Effect> $crate::Walk<'ctx, M, E> for &'ctx $name {
type Walker = $crate::walkers::core::r#struct::StructWalker<'ctx, Info, $crate::any::StaticType, M, E>;
fn into_walker<'e>(self) -> $crate::effect::ErasedEffective<'e, Self::Walker, E> {
E::ready($crate::walkers::core::r#struct::StructWalker::new(self))
}
}
impl<'ctx> $crate::WalkerTypes for &'ctx $name {
type Error = $crate::walkers::core::r#struct::StructWalkError<FieldError<'ctx>>;
type Output = ();
}
$vis enum Info {}
#[derive(Debug)]
#[allow(non_camel_case_types, unused)]
enum FieldErrorKind<'ctx> {$(
$field($crate::walkers::core::key_value::KeyValueError<$crate::never::Never, <&'ctx $type as $crate::WalkerTypes>::Error>)
),*}
#[derive(Debug)]
#[allow(unused)]
$vis struct FieldError<'ctx>(FieldErrorKind<'ctx>);
impl<'ctx, M: 'ctx> $crate::walkers::core::r#struct::StructTypeInfo<'ctx, M> for Info {
const NAME: &'static str = stringify!($name);
const FIELDS: &'static [&'static str] = &[$(stringify!($field)),*];
type FieldError = FieldError<'ctx>;
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, E: $crate::effect::Effect>(
index: usize,
value: &'ctx Self::T,
visitor: $crate::protocol::DynVisitor<'a, 'ctx>,
) -> $crate::effect::ErasedEffective<'a, Result<$crate::Flow, Self::FieldError>, E> {
mod fields {
enum Fields {$($field),*}
$(pub const $field: usize = Fields::$field as usize;)*
}
use $crate::effect::EffectiveExt;
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::<DefaultMode, Blocking>::into_walker(&value);
// let mut visitor = builders::debug::Visitor::<Blocking>::new();
//
// dbg!(Spin::block_on(Walker::<Blocking>::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() {
use crate::effect::blocking::BlockOn as _;
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 });
}
}