working single value protocol
| -rw-r--r-- | src/any.rs | 86 | ||||
| -rw-r--r-- | src/builtins.rs | 8 | ||||
| -rw-r--r-- | src/builtins/visitor/value.rs | 65 | ||||
| -rw-r--r-- | src/lib.rs | 6 | ||||
| -rw-r--r-- | src/protocol.rs | 32 | ||||
| -rw-r--r-- | src/protocol/id.rs | 81 | ||||
| -rw-r--r-- | src/protocol/visitor.rs (renamed from src/builtins/visitor.rs) | 3 | ||||
| -rw-r--r-- | src/protocol/visitor/borrow.rs (renamed from src/builtins/visitor/borrow.rs) | 0 | ||||
| -rw-r--r-- | src/protocol/visitor/request_hint.rs (renamed from src/builtins/visitor/request_hint.rs) | 2 | ||||
| -rw-r--r-- | src/protocol/visitor/sequence.rs (renamed from src/builtins/visitor/sequence.rs) | 0 | ||||
| -rw-r--r-- | src/protocol/visitor/tagged.rs (renamed from src/builtins/visitor/tagged.rs) | 0 | ||||
| -rw-r--r-- | src/protocol/visitor/value.rs | 149 | ||||
| -rw-r--r-- | src/protocol/walker.rs (renamed from src/builtins/walker.rs) | 0 | ||||
| -rw-r--r-- | src/protocol/walker/hint.rs (renamed from src/builtins/walker/hint.rs) | 31 | ||||
| -rw-r--r-- | src/symbol.rs | 6 |
15 files changed, 253 insertions, 216 deletions
@@ -66,17 +66,74 @@ macro_rules! nameable { pub use nameable; pub struct Owned<T: ?Sized>(pub T); -nameable! { - pub ['a, 'lt, T] - Owned<T> where {T: ?Sized} - Owned<T::Nameable> where {T: ?Sized} -} -// pub struct Borrowed<'lt, T: ?Sized>(pub &'lt T); -// nameable!(['a, 'lt: 'a, T: ?Sized + 'static]: Borrowed<'lt, T> => Borrowed<'static, T>); -// -// pub struct MutBorrowed<'lt, T: ?Sized>(pub &'lt mut T); -// nameable!(['a, 'lt: 'a, T: ?Sized + 'static]: MutBorrowed<'lt, T> => MutBorrowed<'static, T>); +const _: () = { + pub struct Name<T: ?Sized>(PhantomData<fn() -> *const T>); + + impl<'a, 'lt, T: ?Sized + 'static> TypeNameable<'a, 'lt> for Owned<T> { + type Name = Name<T>; + } + + impl<'a, 'lt, T: ?Sized + 'static> TypeName<'a, 'lt> for Name<T> { + type Nameable = Owned<T>; + } +}; + +pub struct Borrowed<'lt, T: ?Sized>(pub &'lt T); + +const _: () = { + pub struct Name<T: ?Sized>(PhantomData<fn() -> *const T>); + + impl<'a, 'lt: 'a, T: ?Sized + 'static> TypeNameable<'a, 'lt> for Borrowed<'lt, T> { + type Name = Name<T>; + } + + impl<'a, 'lt: 'a, T: ?Sized + 'static> TypeName<'a, 'lt> for Name<T> { + type Nameable = Borrowed<'lt, T>; + } +}; + +pub struct TempBorrowed<'a, T: ?Sized>(pub &'a T); + +const _: () = { + pub struct Name<T: ?Sized>(PhantomData<fn() -> *const T>); + + impl<'a, 'lt, T: ?Sized + 'static> TypeNameable<'a, 'lt> for TempBorrowed<'a, T> { + type Name = Name<T>; + } + + impl<'a, 'lt, T: ?Sized + 'static> TypeName<'a, 'lt> for Name<T> { + type Nameable = TempBorrowed<'a, T>; + } +}; + +pub struct BorrowedMut<'lt, T: ?Sized>(pub &'lt mut T); + +const _: () = { + pub struct Name<T: ?Sized>(PhantomData<fn() -> *const T>); + + impl<'a, 'lt: 'a, T: ?Sized + 'static> TypeNameable<'a, 'lt> for BorrowedMut<'lt, T> { + type Name = Name<T>; + } + + impl<'a, 'lt: 'a, T: ?Sized + 'static> TypeName<'a, 'lt> for Name<T> { + type Nameable = BorrowedMut<'lt, T>; + } +}; + +pub struct TempBorrowedMut<'lt, T: ?Sized>(pub &'lt mut T); + +const _: () = { + pub struct Name<T: ?Sized>(PhantomData<fn() -> *const T>); + + impl<'a, 'lt, T: ?Sized + 'static> TypeNameable<'a, 'lt> for TempBorrowedMut<'a, T> { + type Name = Name<T>; + } + + impl<'a, 'lt, T: ?Sized + 'static> TypeName<'a, 'lt> for Name<T> { + type Nameable = TempBorrowedMut<'a, T>; + } +}; // box here @@ -149,7 +206,7 @@ pub trait AnyTrait<'lt> { 'lt: 'a; } -impl<'lt> dyn AnyTrait<'lt> { +impl<'lt> dyn AnyTrait<'lt> + '_ { pub fn upcast<'a, Trait: ?Sized + TypeNameable<'a, 'lt>>(&'a self) -> Option<&'a Trait> { self.upcast_to_id(LtTypeId::of::<Trait>()) .map(|object| match object.downcast::<Trait>() { @@ -163,7 +220,9 @@ impl<'lt> dyn AnyTrait<'lt> { }) } - pub fn upcast_mut<'a, Trait: ?Sized + TypeNameable<'a, 'lt>>(&'a mut self) -> Option<&'a mut Trait> { + pub fn upcast_mut<'a, Trait: ?Sized + TypeNameable<'a, 'lt>>( + &'a mut self, + ) -> Option<&'a mut Trait> { self.upcast_to_id_mut(LtTypeId::of::<Trait>()) .map(|object| match object.downcast::<Trait>() { Ok(object) => object, @@ -219,7 +278,6 @@ macro_rules! any_trait { #[doc(inline)] pub use any_trait; - #[must_use] pub struct IndirectLtAny<'a, 'lt: 'a, I: Indirect<'a>> { info: fn() -> (LtTypeId<'lt>, unsafe fn(RawIndirect)), @@ -440,7 +498,7 @@ mod test { } let x = X(42); - let y: &dyn AnyTrait = &x; + let y: &dyn AnyTrait<'_> = &x; let z: &dyn Z = y.upcast().unwrap(); assert_eq!(z.num(), 42); } diff --git a/src/builtins.rs b/src/builtins.rs index dba09ab..e69de29 100644 --- a/src/builtins.rs +++ b/src/builtins.rs @@ -1,8 +0,0 @@ -use crate::any::AnyTrait; - -pub mod visitor; -pub mod walker; - -pub type Visitor<'a, 'ctx> = &'a mut dyn AnyTrait<'ctx>; -pub type Walker<'a, 'ctx> = &'a mut dyn AnyTrait<'ctx>; -pub type ControlFlow<B = (), C = ()> = core::ops::ControlFlow<B, C>; diff --git a/src/builtins/visitor/value.rs b/src/builtins/visitor/value.rs deleted file mode 100644 index aa35891..0000000 --- a/src/builtins/visitor/value.rs +++ /dev/null @@ -1,65 +0,0 @@ -//! [`Protocol`] for giving a visitor an owned value. -//! -//! In some sense, this is the most basic protocol. - -use core::{marker::PhantomData, ops::ControlFlow}; - -use crate::{builtins::walker::hint::Meta, protocol::Protocol}; - -/// [`Protocol`] for giving a visitor an owned value. -/// -/// A value of type `T` can be given to the visitor using -/// [`Object::visit()`]. There is a restriction that `T: 'static`. -pub struct Value<T>(PhantomData<fn() -> T>); - -/// Trait object for the [`Value`] protocol. -/// -/// Types implementing the [`Value`] protocol will implement this trait. -pub trait Object<T> { - /// Visit a value of type `T`. - /// - /// Use this to give a value to a visitor. Its expected that a walker - /// only calls this once per usage of the trait object, but that is not - /// forced. - /// - /// If a [`ControlFlow::Break`] is returned then the walker - /// should stop walking as soon as possible as there has likely been - /// and error. - fn visit(&mut self, value: T) -> ControlFlow<()>; -} - -// This is what makes Value a protocol. -impl<T: 'static> Protocol for Value<T> { - type Object<'a, 'ctx: 'a> = &'a mut dyn Object<T>; -} - -// This enrolls the Value protocol into the walker hint system. -impl<T: 'static> Meta for Value<T> { - type Known<'a, 'ctx: 'a> = (); - - type Hint<'a, 'ctx: 'a> = (); -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn visit() { - struct Visitor(Option<i32>); - - impl Object<i32> for Visitor { - fn visit(&mut self, value: i32) -> ControlFlow<()> { - self.0 = Some(value); - ControlFlow::Continue(()) - } - } - - let mut v = Visitor(None); - let object: <Value<i32> as Protocol>::Object<'_, '_> = &mut v; - object.visit(42); - - assert_eq!(v.0, Some(42)); - } -} - @@ -3,13 +3,15 @@ #![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 builtins; -// pub mod protocol; +// pub mod builtins; +pub mod protocol; pub mod symbol; // mod walk; diff --git a/src/protocol.rs b/src/protocol.rs index ba5826d..f06f095 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -33,31 +33,11 @@ //! This is done via the help of the [`AnyImpl`] type. This is not required for the core //! idea of DIDETs. -use crate::any::{IndirectLtAny, LtAny, LtTypeId, Mut, Ref, TypeNameable}; +use crate::any::AnyTrait; -#[cfg(test)] -mod test { - use crate::nameable; +pub mod visitor; +pub mod walker; - use super::*; - - #[test] - fn implementer_macro() { - trait Z {} - - nameable! { - ['a, 'ctx] - dyn Z + 'a where {'ctx: 'a} - } - - struct X<T>(T); - - impl<T: Clone> Z for X<T> {} - - implementer! { - impl['a, 'ctx, T: Clone] X<T> = [ - dyn Z + 'a - ]; - } - } -} +pub type Visitor<'a, 'ctx> = &'a mut dyn AnyTrait<'ctx>; +pub type Walker<'a, 'ctx> = &'a mut dyn AnyTrait<'ctx>; +pub type ControlFlow<B = (), C = ()> = core::ops::ControlFlow<B, C>; diff --git a/src/protocol/id.rs b/src/protocol/id.rs deleted file mode 100644 index 40aa2bc..0000000 --- a/src/protocol/id.rs +++ /dev/null @@ -1,81 +0,0 @@ -use core::any::TypeId; - -use super::Protocol; - -/// ID of a protocol. -/// -/// An ID also includes the protocol's type name for easier debugging. -#[derive(Copy, Clone)] -pub struct ProtocolId { - /// Type ID of the protocol type. - id: fn() -> TypeId, - - /// Name of the protocol type. - name: fn() -> &'static str, -} - -impl ProtocolId { - /// Get the ID of a protocol. - pub const fn of<P: Protocol>() -> Self { - Self { - id: || core::any::TypeId::of::<P>(), - name: || core::any::type_name::<P>(), - } - } - - /// Type ID of the protocol. - /// - /// This is used for comparision. - fn id(&self) -> TypeId { - (self.id)() - } - - /// Type name of the protocol. - /// - /// This is used for debugging purposes. - fn name(&self) -> &'static str { - (self.name)() - } -} - -impl core::fmt::Debug for ProtocolId { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("ProtocolId") - .field("id", &self.id()) - .field("name", &self.name()) - .finish() - } -} - -impl core::fmt::Display for ProtocolId { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - // Just print the type name. - self.name().fmt(f) - } -} - -impl PartialEq for ProtocolId { - fn eq(&self, other: &Self) -> bool { - self.id() == other.id() - } -} - -impl Eq for ProtocolId {} - -impl PartialOrd for ProtocolId { - fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> { - Some(self.cmp(other)) - } -} - -impl Ord for ProtocolId { - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - self.id().cmp(&other.id()) - } -} - -impl core::hash::Hash for ProtocolId { - fn hash<H: core::hash::Hasher>(&self, state: &mut H) { - self.id().hash(state); - } -} diff --git a/src/builtins/visitor.rs b/src/protocol/visitor.rs index 4fb5b25..b85f512 100644 --- a/src/builtins/visitor.rs +++ b/src/protocol/visitor.rs @@ -1,7 +1,8 @@ mod request_hint; // pub mod sequence; // pub mod tagged; -// pub mod value; +mod value; // pub mod borrow; pub use request_hint::*; +pub use value::*; diff --git a/src/builtins/visitor/borrow.rs b/src/protocol/visitor/borrow.rs index 511d429..511d429 100644 --- a/src/builtins/visitor/borrow.rs +++ b/src/protocol/visitor/borrow.rs diff --git a/src/builtins/visitor/request_hint.rs b/src/protocol/visitor/request_hint.rs index 747fa8e..bd5b12d 100644 --- a/src/builtins/visitor/request_hint.rs +++ b/src/protocol/visitor/request_hint.rs @@ -1,6 +1,6 @@ use core::ops::ControlFlow; -use crate::{nameable, any::AnyTrait, builtins::Walker}; +use crate::{nameable, protocol::Walker}; /// Protocol for requesting a hint from a visitor. pub trait RequestHint<'ctx> { diff --git a/src/builtins/visitor/sequence.rs b/src/protocol/visitor/sequence.rs index b143c12..b143c12 100644 --- a/src/builtins/visitor/sequence.rs +++ b/src/protocol/visitor/sequence.rs diff --git a/src/builtins/visitor/tagged.rs b/src/protocol/visitor/tagged.rs index c447a5f..c447a5f 100644 --- a/src/builtins/visitor/tagged.rs +++ b/src/protocol/visitor/tagged.rs diff --git a/src/protocol/visitor/value.rs b/src/protocol/visitor/value.rs new file mode 100644 index 0000000..87dbd47 --- /dev/null +++ b/src/protocol/visitor/value.rs @@ -0,0 +1,149 @@ +//! [`Protocol`] for giving a visitor an owned value. +//! +//! In some sense, this is the most basic protocol. + +use crate::{ + nameable, + protocol::{walker::HintMeta, ControlFlow}, +}; + +/// Trait object for the [`Value`] protocol. +/// +/// Types implementing the [`Value`] protocol will implement this trait. +pub trait Value<T> { + /// Visit a value of type `T`. + /// + /// Use this to give a value to a visitor. Its expected that a walker + /// only calls this once per usage of the trait object, but that is not + /// forced. + /// + /// If a [`ControlFlow::Break`] is returned then the walker + /// should stop walking as soon as possible as there has likely been + /// and error. + fn visit(&mut self, value: T) -> ControlFlow; +} + +nameable! { + pub ['a, 'ctx, T] + dyn Value<T> + 'a where {T: ?Sized} + dyn Value<T::Nameable> + 'a where {T: ?Sized} +} + +// This enrolls the Value protocol into the walker hint system. +impl<'ctx, T> HintMeta<'ctx> for dyn Value<T> + '_ { + type Known<'a> = () where 'ctx: 'a; + + type Hint = (); +} + +#[cfg(test)] +mod test { + use crate::{ + any::{AnyTrait, Borrowed, BorrowedMut, Owned}, + any_trait, + }; + + use super::*; + + #[test] + fn visit() { + struct Visitor(Option<i32>); + + impl Value<Owned<i32>> for Visitor { + fn visit(&mut self, Owned(value): Owned<i32>) -> ControlFlow<()> { + self.0 = Some(value); + ControlFlow::Continue(()) + } + } + + impl Value<Borrowed<'_, i32>> for Visitor { + fn visit(&mut self, Borrowed(value): Borrowed<'_, i32>) -> ControlFlow<()> { + self.0 = Some(*value); + ControlFlow::Continue(()) + } + } + + any_trait! { + impl['a, 'ctx] Visitor = [ + dyn Value<Owned<i32>>, + dyn Value<Borrowed<'ctx, i32>>, + ]; + } + + let mut v = Visitor(None); + let object: &mut dyn AnyTrait<'_> = &mut v; + object + .upcast_mut::<dyn Value<Owned<i32>>>() + .unwrap() + .visit(Owned(42)); + + assert_eq!(v.0, Some(42)); + + let object: &mut dyn AnyTrait<'_> = &mut v; + object + .upcast_mut::<dyn Value<Borrowed<'_, i32>>>() + .unwrap() + .visit(Borrowed(&101)); + + assert_eq!(v.0, Some(101)); + } + + #[test] + fn visit_borrowed() { + struct Visitor<'ctx>(Option<&'ctx mut String>); + + impl<'ctx> Value<BorrowedMut<'ctx, String>> for Visitor<'ctx> { + fn visit(&mut self, BorrowedMut(value): BorrowedMut<'ctx, String>) -> ControlFlow<()> { + self.0 = Some(value); + ControlFlow::Continue(()) + } + } + + any_trait! { + impl['a, 'ctx] Visitor<'ctx> = [ + dyn Value<BorrowedMut<'ctx, String>> + 'a, + ]; + } + + let mut v = Visitor(None); + + let mut y = String::from("abc"); + let object: &mut dyn AnyTrait<'_> = &mut v; + object + .upcast_mut::<dyn Value<_>>() + .unwrap() + .visit(BorrowedMut(&mut y)); + + v.0.unwrap().push_str("def"); + assert_eq!(y, "abcdef"); + } + + #[test] + fn visit_borrowed_unsized() { + struct Visitor<'ctx>(Option<&'ctx str>); + + impl<'ctx> Value<Borrowed<'ctx, str>> for Visitor<'ctx> { + fn visit(&mut self, Borrowed(value): Borrowed<'ctx, str>) -> ControlFlow<()> { + self.0 = Some(value); + ControlFlow::Continue(()) + } + } + + any_trait! { + impl['a, 'ctx] Visitor<'ctx> = [ + dyn Value<Borrowed<'ctx, str>> + 'a, + ]; + } + + let mut v = Visitor(None); + + let y = String::from("abc"); + let object: &mut dyn AnyTrait<'_> = &mut v; + object + .upcast_mut::<dyn Value<Borrowed<'_, str>>>() + .unwrap() + .visit(Borrowed(&y)); + + assert_eq!(v.0, Some("abc")); + } +} diff --git a/src/builtins/walker.rs b/src/protocol/walker.rs index 27ee8c5..27ee8c5 100644 --- a/src/builtins/walker.rs +++ b/src/protocol/walker.rs diff --git a/src/builtins/walker/hint.rs b/src/protocol/walker/hint.rs index a386f24..fdcc46a 100644 --- a/src/builtins/walker/hint.rs +++ b/src/protocol/walker/hint.rs @@ -4,10 +4,9 @@ //! this module gives a protocol by which a visitor can give a hint //! to the walker about what it is expecting. -use core::{marker::PhantomData}; - use crate::{ - nameable, any::AnyTrait, builtins::{Visitor, ControlFlow}, + nameable, + protocol::{ControlFlow, Visitor}, }; /// Meta information for the hint. @@ -18,10 +17,12 @@ pub trait HintMeta<'ctx> { /// /// This should be information easy to get without changing the state of the walker /// in an irreversable way. - type Known<'a>; + type Known<'a> + where + 'ctx: 'a; /// Extra information the visitor can give to the walker about what it is expecting. - type Hint<'a>; + type Hint; } /// Object implementing the [`Hint`] protocol. @@ -29,10 +30,10 @@ pub trait Hint<'ctx, Protocol: HintMeta<'ctx>> { /// Hint to the walker to use the `P` protocol. /// /// This should only be called once per [`RequestHint`]. - fn hint(&mut self, visitor: Visitor<'_, 'ctx>, hint: Protocol::Hint<'_>) -> ControlFlow; + fn hint(&mut self, visitor: Visitor<'_, 'ctx>, hint: Protocol::Hint) -> ControlFlow; /// Ask the walker for information about it's support of the protocol. - fn known(&mut self, hint: &Protocol::Hint<'_>) -> ControlFlow<(), Protocol::Known<'_>>; + fn known(&mut self, hint: &Protocol::Hint) -> ControlFlow<(), Protocol::Known<'_>>; } nameable! { @@ -60,28 +61,28 @@ mod test { impl<'ctx, X> Hint<'ctx, Y> for X { fn hint( &mut self, - visitor: &mut dyn AnyTrait<'ctx>, - hint: <Y as HintMeta>::Hint<'_>, + visitor: Visitor<'_, 'ctx>, + hint: <Y as HintMeta<'_>>::Hint, ) -> ControlFlow<()> { todo!() } fn known( &mut self, - hint: &<Y as HintMeta>::Hint<'_>, - ) -> ControlFlow<(), <Y as HintMeta>::Known<'_>> { + hint: &<Y as HintMeta<'_>>::Hint, + ) -> ControlFlow<(), <Y as HintMeta<'_>>::Known<'_>> { todo!() } } impl<'ctx> HintMeta<'ctx> for Y { - type Known<'a> = (); + type Known<'a> = () where 'ctx: 'a; - type Hint<'a> = (); + type Hint = (); } let x = X; - let y: &dyn Hint<Y> = &x; + let y: &dyn Hint<'_, Y> = &x; fn id<'a, 'ctx, T: ?Sized + TypeNameable<'a, 'ctx>>(x: &T) { dbg!(LtTypeId::of::<T>()); @@ -89,6 +90,6 @@ mod test { id(y); - todo!(); + // todo!(); } } diff --git a/src/symbol.rs b/src/symbol.rs index 1e13344..7e1ee46 100644 --- a/src/symbol.rs +++ b/src/symbol.rs @@ -65,7 +65,7 @@ impl Symbol { /// is too complex to store in the symbol then a /// [`EncodeError::TooComplex`] error is returned. If this happens try using /// a shorter tag and/or remove capitals and numbers. - pub const fn try_new(tag: &str) -> Result<Self, EncodeError> { + pub const fn try_new(tag: &str) -> Result<Self, EncodeError<'_>> { match encode(tag) { Ok(tag) => Ok(Self(tag)), Err(err) => Err(err), @@ -192,7 +192,7 @@ impl<'a> core::fmt::Display for EncodeError<'a> { impl<'a> std::error::Error for EncodeError<'a> {} // Decode an arithmetic coded int into a string. -fn decode(input: u64, f: &mut core::fmt::Formatter) -> core::fmt::Result { +fn decode(input: u64, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { // The interval and a range in that interval. let (interval, mut range) = Interval::new(); @@ -358,7 +358,7 @@ fn bit(precision: &mut u64, offset: &mut u64, input: u64) -> Option<u64> { // Arithmetic code a string into a int. // // This is a type of compression. -const fn encode(input: &str) -> Result<u64, EncodeError> { +const fn encode(input: &str) -> Result<u64, EncodeError<'_>> { // Interval and current range in that interval. let (interval, mut range) = Interval::new(); |