11use crate :: value:: Value ;
22use std:: rc:: Rc ;
33
4- // @TODO should we just exclusively call them protocols as
5- // we've been doing (deciding that Clojure without the host
6- // has Protocols as its natural abstraction for interfaces)
7- // or should interfaces, as an abstraction, exist (and perhaps
8- // be used by Protocols even?)
94/// A type that implements Protocol is one that has a pseudo downcasting of
105///
116/// value.as::<ISeq>()
@@ -16,26 +11,154 @@ use std::rc::Rc;
1611/// functions to the Value inside, and unwrap() it to get your Value back when
1712/// you're done
1813pub trait Protocol : Sized {
19- fn try_as_protocol ( val : & Rc < Value > ) -> Option < Self > ; // where Self:Sized;
14+ fn instanceof ( val : & Rc < Value > ) -> bool ;
15+
16+ // The following exist so we can build the rest of the trait functions on this generic behavior
17+ /// Simply wraps the value in this protocol
18+ /// whether its a valid cast or not
19+ fn raw_wrap ( val : & Rc < Value > ) -> Self ;
20+
21+ /// Simply retrieves the Rc<Value> stored in the Protocol,
22+ /// whether its valid or not
23+ fn raw_unwrap ( & self ) -> Rc < Value > ;
24+
25+ // @TODO consider renaming downcast
26+ fn try_as_protocol ( val : & Rc < Value > ) -> Option < Self > {
27+ if Self :: instanceof ( val) {
28+ Some ( Self :: raw_wrap ( val) )
29+ }
30+ else {
31+ None
32+ }
33+ }
34+
2035 /// Panics if your Value isn't an instance of Protocol
2136 fn as_protocol ( val : & Rc < Value > ) -> Self {
2237 Self :: try_as_protocol ( val) . unwrap ( )
2338 }
24- fn try_unwrap ( & self ) -> Option < Rc < Value > > ;
25- /// Panics if your Value isn't an instance of Protocol
39+
40+ fn try_unwrap ( & self ) -> Option < Rc < Value > > {
41+ let inner_value = self . raw_unwrap ( ) ;
42+ if Self :: instanceof ( & inner_value) {
43+ Some ( inner_value)
44+ }
45+ else {
46+ None
47+ }
48+ }
49+ // Realistically, the fact that you unwrap to get an upcast is just an implementation detail, so
50+ // @TODO change to upcast
51+ /// Panics if Value not instance of Protocol
2652 fn unwrap ( & self ) -> Rc < Value > {
2753 self . try_unwrap ( ) . unwrap ( )
2854 }
2955}
3056pub trait ProtocolCastable {
57+ fn instanceof < T : Protocol > ( & self ) -> bool ;
3158 fn try_as_protocol < T : Protocol > ( & self ) -> Option < T > ;
3259 fn as_protocol < T : Protocol > ( & self ) -> T ;
3360}
61+
3462impl ProtocolCastable for Rc < Value > {
63+ fn instanceof < T : Protocol > ( & self ) -> bool {
64+ T :: instanceof ( self )
65+ }
3566 fn try_as_protocol < T : Protocol > ( & self ) -> Option < T > {
3667 T :: try_as_protocol ( self )
3768 }
3869 fn as_protocol < T : Protocol > ( & self ) -> T {
3970 T :: as_protocol ( self )
4071 }
4172}
73+
74+ // @TODO Consider changing syntax to differentiate protocol from variants
75+ // @TODO Consider trade offs of having a very plain function like macro of macro!(a,b,c)
76+ // and having a clearer one like define_protocol(Iterable = A | B | C)
77+ #[ macro_export]
78+ macro_rules! define_protocol {
79+ // define_protocol!(Protocol = A | B)
80+ ( $protocol: ident = $( $variant: ident) |* ) => {
81+ #[ derive( Debug , Clone ) ]
82+ pub struct $protocol {
83+ value: Rc <Value >
84+ }
85+ impl crate :: protocol:: Protocol for $protocol {
86+ fn raw_wrap( val: & Rc <Value >) -> Self {
87+ $protocol { value: Rc :: clone( val) }
88+ }
89+ fn raw_unwrap( & self ) -> Rc <Value > {
90+ Rc :: clone( & self . value)
91+ }
92+ fn instanceof( val: & Rc <Value >) -> bool {
93+ match & * * val {
94+ $(
95+ crate :: value:: Value :: $variant( _) => true ,
96+ ) *
97+ _ => false
98+ }
99+ }
100+ }
101+ } ;
102+ ( $protocol: ident, $( $variant: ident) , * ) => {
103+ #[ derive( Debug , Clone ) ]
104+ pub struct $protocol {
105+ value: Rc <Value >
106+ }
107+ impl crate :: protocol:: Protocol for $protocol {
108+ fn raw_wrap( val: & Rc <Value >) -> Self {
109+ $protocol { value: Rc :: clone( val) }
110+ }
111+ fn raw_unwrap( & self ) -> Rc <Value > {
112+ Rc :: clone( & self . value)
113+ }
114+ fn instanceof( val: & Rc <Value >) -> bool {
115+ match & * * val {
116+ $(
117+ crate :: value:: Value :: $variant( _) => true ,
118+ ) *
119+ _ => false
120+ }
121+ }
122+ }
123+ } ;
124+ }
125+ // @TODO next trick; extend_protocol, so that it actually wraps trait equivalent of protocol
126+ // Ie, make it so that protocol::IFn is itself of trait IFn, and automatically
127+ // wraps its trait functions
128+ // @TODO Think, however, whether its worth it to always have a trait and protocol
129+ // I believe so -- I think basically the idea is the trait wraps true Rust values,
130+ // like symbol::Symbol, and the protocol wraps its ClojureRS equivalent, like Value::Symbol
131+ //
132+ //
133+ // traits and traits are both to give us interface behavior, traits give that to us
134+ // for our rust primitives like symbol::Symbol, but too much of the power of both is at compile time.
135+ // Just as we made the Value to give us a value whose rust type could be unknown at runtime,
136+ // we created the Protocol to give us an interface we could cast Values to and from at runtime,
137+ // as well as some other benefits we need
138+ //
139+ // macro_rules! extend_protocol {
140+ // ($protocol:ident, $fn_name:ident, $fn:expr, $($variant:ident), *) => {
141+ //
142+ // impl $protocol {
143+ // fn $fn_name(val: &Rc<Value>) -> Option<Self> {
144+ // match &**val {
145+ // $(
146+ // crate::value::Value::$variant(_) => Some($protocol {
147+ // value: Rc::clone(val),
148+ // }),
149+ // )*
150+ // _ => None
151+ // }
152+ // }
153+ // fn try_unwrap(&self) -> Option<Rc<Value>> {
154+ // match &*self.value {
155+ // $(
156+ // crate::value::Value::$variant(_) => Some(Rc::clone(&self.value)),
157+ // )*
158+ // _ => None
159+ // }
160+ // }
161+ // }
162+ // };
163+ // }
164+ //
0 commit comments