3030//! trait is defined, which collects requirements for message types using
3131//! multicast.
3232
33- use std:: collections:: HashMap ;
33+ use std:: collections:: VecDeque ;
3434use std:: marker:: PhantomData ;
3535
3636use serde:: Deserialize ;
@@ -47,34 +47,20 @@ use crate::actor::RemoteActor;
4747use crate :: data:: Serialized ;
4848use crate :: intern_typename; // for macros
4949
50- /// A message `M ` that is [`Unbind`] can be converted into an [`Unbound<M>`]
51- /// containing the message along with a set of extracted parameters that can
52- /// be independently manipulated, and then later reconstituted (rebound) into
53- /// an `M `-typed message again.
50+ /// An object `T ` that is [`Unbind`] can extract a set of parameters from itself,
51+ /// and store in [`Bindings`]. The extracted parameters in [`Bindings`] can be
52+ /// independently manipulated, and then later reconstituted (rebound) into
53+ /// a `T `-typed object again.
5454pub trait Unbind : Sized {
55- /// Unbinds the message into an envelope [`Unbound<M>`] containing
56- /// the message along with extracted parameters that can are
57- /// independently accessible.
58- fn unbind ( self ) -> anyhow:: Result < Unbound < Self > > {
59- let bindings = self . bindings ( ) ?;
60- Ok ( Unbound {
61- message : self ,
62- bindings,
63- } )
64- }
65-
66- /// Get the bindings of this message.
67- fn bindings ( & self ) -> anyhow:: Result < Bindings > ;
55+ /// Extract parameters from itself and store them in bindings.
56+ fn unbind ( & self , bindings : & mut Bindings ) -> anyhow:: Result < ( ) > ;
6857}
6958
70- /// A message `M` that is [`Bind`] can bind a set of externally provided
71- /// parameters into the message. It is intended to be used in conjunction
72- /// with [`Unbind`] to extract portions of a message, manipulate these
73- /// independently, and then reconstitute the message.
59+ /// An object `T` that is [`Bind`] can bind a set of externally provided
60+ /// parameters into itself.
7461pub trait Bind : Sized {
75- /// Update itself with information contained in bindings, and return the
76- /// result.
77- fn bind ( self , bindings : & Bindings ) -> anyhow:: Result < Self > ;
62+ /// Remove parameters from bindings, and use them to update itself.
63+ fn bind ( & mut self , bindings : & mut Bindings ) -> anyhow:: Result < ( ) > ;
7864}
7965
8066/// This trait collects the necessary requirements for messages that are can be
@@ -85,78 +71,50 @@ impl<T: RemoteMessage + Bind + Unbind> Castable for T {}
8571/// Information extracted from a message through [Unbind], which can be merged
8672/// back to the message through [Bind].
8773#[ derive( Debug , Default , Clone , PartialEq , Serialize , Deserialize ) ]
88- pub struct Bindings ( HashMap < u64 , Vec < Serialized > > ) ;
74+ pub struct Bindings ( VecDeque < ( u64 , Serialized ) > ) ;
8975
9076impl Bindings {
91- /// Inserts values into the binding.
92- /// If the binding did not have this type present, None is returned.
93- /// If the binding already had this type, replace the old values with new
94- /// values, and the old value is returned.
95- pub fn insert < T : Serialize + Named > (
96- & mut self ,
97- values : impl IntoIterator < Item = & T > ,
98- ) -> anyhow:: Result < Option < Vec < Serialized > > > {
99- let ser = values
100- . into_iter ( )
101- . map ( |v| Serialized :: serialize ( v) )
102- . collect :: < Result < Vec < Serialized > , _ > > ( ) ?;
103- Ok ( self . 0 . insert ( T :: typehash ( ) , ser) )
104- }
105-
106- /// Appends an element to the back of its type's corresponding vector in the
107- /// binding.
108- pub fn push < T : Serialize + Named > ( & mut self , value : & T ) -> anyhow:: Result < ( ) > {
77+ /// Push a value into this bindings.
78+ pub fn push_back < T : Serialize + Named > ( & mut self , value : & T ) -> anyhow:: Result < ( ) > {
10979 let ser = Serialized :: serialize ( value) ?;
110- self . 0 . entry ( T :: typehash ( ) ) . or_default ( ) . push ( ser) ;
80+ self . 0 . push_back ( ( T :: typehash ( ) , ser) ) ;
11181 Ok ( ( ) )
11282 }
11383
114- /// Get this type's values from the binding.
115- /// If the binding did not have this type present, empty Vec is returned.
116- pub fn get < T : DeserializeOwned + Named > ( & self ) -> anyhow:: Result < Vec < T > > {
117- match self . 0 . get ( & T :: typehash ( ) ) {
118- None => Ok ( vec ! [ ] ) ,
119- Some ( ser) => {
120- let deser = ser
121- . iter ( )
122- . map ( |v| v. deserialized :: < T > ( ) )
123- . collect :: < Result < Vec < T > , _ > > ( ) ?;
124- Ok ( deser)
84+ /// Removes the first pushed element in this bindings, deserialize it into
85+ /// type T, and return it. Return [`None`] if this bindings is empty.
86+ /// If the type of the first pushed element does not match T, an error is
87+ /// returned.
88+ pub fn pop_front < T : DeserializeOwned + Named > ( & mut self ) -> anyhow:: Result < Option < T > > {
89+ match self . 0 . pop_front ( ) {
90+ None => Ok ( None ) ,
91+ Some ( ( t, v) ) => {
92+ if t != T :: typehash ( ) {
93+ anyhow:: bail!(
94+ "type mismatch: expected {} with hash {}, found {} in binding" ,
95+ T :: typename( ) ,
96+ T :: typehash( ) ,
97+ t,
98+ ) ;
99+ }
100+ Ok ( Some ( v. deserialized :: < T > ( ) ?) )
125101 }
126102 }
127103 }
128104
129- /// Rebind all values of type `T`. The input iterator must exactly match the
130- /// number of `T`-typed values in the binding.
131- pub fn rebind < T : DeserializeOwned + Named > (
132- & self ,
133- mut_refs : impl ExactSizeIterator < Item = & mut T > ,
105+ fn visit_mut < T : Serialize + DeserializeOwned + Named > (
106+ & mut self ,
107+ mut f : impl FnMut ( & mut T ) -> anyhow:: Result < ( ) > ,
134108 ) -> anyhow:: Result < ( ) > {
135- let bound_values = self . get :: < T > ( ) ?;
136- anyhow:: ensure!(
137- bound_values. len( ) == mut_refs. len( ) ,
138- "the length of type {} in binding is {}, which is different from the length of \
139- references it binds to {}.",
140- T :: typename( ) ,
141- bound_values. len( ) ,
142- mut_refs. len( ) ,
143- ) ;
144-
145- for ( p_ref, p) in mut_refs. zip ( bound_values. into_iter ( ) ) {
146- * p_ref = p;
109+ for v in self . 0 . iter_mut ( ) {
110+ if v. 0 == T :: typehash ( ) {
111+ let mut t = v. 1 . deserialized :: < T > ( ) ?;
112+ f ( & mut t) ?;
113+ v. 1 = Serialized :: serialize ( & t) ?;
114+ }
147115 }
148116 Ok ( ( ) )
149117 }
150-
151- /// Returns true if the binding contains no values of type `T`.
152- pub fn is_empty < T : Named > ( & self ) -> bool {
153- self . 0 . get ( & T :: typehash ( ) ) . is_none_or ( Vec :: is_empty)
154- }
155-
156- /// Returns the number of values of type `T` in the binding.
157- pub fn len < T : Named > ( & self ) -> usize {
158- self . 0 . get ( & T :: typehash ( ) ) . map_or ( 0 , Vec :: len)
159- }
160118}
161119
162120/// An object contains a message, and its bindings extracted through [Unbind].
@@ -175,8 +133,25 @@ impl<M> Unbound<M> {
175133
176134impl < M : Bind > Unbound < M > {
177135 /// Bind its bindings to its message through [Bind], and return the result.
178- pub fn bind ( self ) -> anyhow:: Result < M > {
179- self . message . bind ( & self . bindings )
136+ pub fn bind ( mut self ) -> anyhow:: Result < M > {
137+ self . message . bind ( & mut self . bindings ) ?;
138+ anyhow:: ensure!(
139+ self . bindings. 0 . is_empty( ) ,
140+ "there are still {} elements left in bindings" ,
141+ self . bindings. 0 . len( )
142+ ) ;
143+ Ok ( self . message )
144+ }
145+ }
146+
147+ impl < M : Unbind > Unbound < M > {
148+ /// Create an object from a typed message.
149+ // Note: cannot implement TryFrom<T> due to conflict with core crate's blanket impl.
150+ // More can be found in this issue: https://github.com/rust-lang/rust/issues/50133
151+ pub fn try_from_message ( message : M ) -> anyhow:: Result < Self > {
152+ let mut bindings = Bindings :: default ( ) ;
153+ message. unbind ( & mut bindings) ?;
154+ Ok ( Unbound { message, bindings } )
180155 }
181156}
182157
@@ -200,38 +175,21 @@ impl ErasedUnbound {
200175 // Note: cannot implement TryFrom<T> due to conflict with core crate's blanket impl.
201176 // More can be found in this issue: https://github.com/rust-lang/rust/issues/50133
202177 pub fn try_from_message < T : Unbind + Serialize + Named > ( msg : T ) -> Result < Self , anyhow:: Error > {
203- let unbound = msg . unbind ( ) ?;
178+ let unbound = Unbound :: try_from_message ( msg ) ?;
204179 let serialized = Serialized :: serialize ( & unbound. message ) ?;
205180 Ok ( Self {
206181 message : serialized,
207182 bindings : unbound. bindings ,
208183 } )
209184 }
210185
211- /// Get ports inside bindings.
212- pub fn get < T : DeserializeOwned + Named > ( & self ) -> anyhow:: Result < Vec < T > > {
213- self . bindings . get ( )
214- }
215-
216- /// Update ports inside bindings.
217- pub fn replace < T : Serialize + Named > (
186+ /// Use the provided function to update values inside bindings in the same
187+ /// order as they were pushed into bindings.
188+ pub fn visit_mut < T : Serialize + DeserializeOwned + Named > (
218189 & mut self ,
219- new_values : impl ExactSizeIterator < Item = & T > ,
190+ f : impl FnMut ( & mut T ) -> anyhow :: Result < ( ) > ,
220191 ) -> anyhow:: Result < ( ) > {
221- anyhow:: ensure!( self . bindings. len:: <T >( ) == new_values. len( ) ) ;
222- self . bindings . insert ( new_values) ?;
223- Ok ( ( ) )
224- }
225-
226- /// Replace all `T`-typed values in the binding with `new_value`.
227- pub fn maybe_replace < T : Serialize + Named > ( & mut self , new_value : & T ) -> anyhow:: Result < bool > {
228- let n = self . bindings . len :: < T > ( ) ;
229- if n == 0 {
230- return Ok ( false ) ;
231- }
232-
233- self . bindings . insert ( vec ! [ new_value; n] ) ?;
234- Ok ( true )
192+ self . bindings . visit_mut ( f)
235193 }
236194
237195 fn downcast < M : DeserializeOwned > ( self ) -> anyhow:: Result < Unbound < M > > {
@@ -289,20 +247,20 @@ impl<M: Named + 'static> Named for IndexedErasedUnbound<M> {
289247macro_rules! impl_bind_unbind_basic {
290248 ( $t: ty) => {
291249 impl Bind for $t {
292- fn bind( self , bindings: & Bindings ) -> anyhow:: Result <Self > {
250+ fn bind( & mut self , bindings: & mut Bindings ) -> anyhow:: Result <( ) > {
293251 anyhow:: ensure!(
294252 bindings. 0 . is_empty( ) ,
295- "bindings for {} should be empty, but got {:?} " ,
253+ "bindings for {} should be empty, but found {} elements left " ,
296254 stringify!( $t) ,
297- bindings
255+ bindings. 0 . len ( ) ,
298256 ) ;
299- Ok ( self )
257+ Ok ( ( ) )
300258 }
301259 }
302260
303261 impl Unbind for $t {
304- fn bindings ( & self ) -> anyhow:: Result <Bindings > {
305- Ok ( Bindings :: default ( ) )
262+ fn unbind ( & self , _bindings : & mut Bindings ) -> anyhow:: Result <( ) > {
263+ Ok ( ( ) )
306264 }
307265 }
308266 } ;
@@ -328,7 +286,6 @@ impl_bind_unbind_basic!(String);
328286mod tests {
329287 use hyperactor:: PortRef ;
330288 use hyperactor:: id;
331- use maplit:: hashmap;
332289
333290 use super :: * ;
334291 use crate :: PortId ;
@@ -348,20 +305,19 @@ mod tests {
348305
349306 // TODO(pzhang) add macro to auto-gen this implementation.
350307 impl Unbind for MyMessage {
351- fn bindings ( & self ) -> anyhow:: Result < Bindings > {
352- let mut bindings = Bindings :: default ( ) ;
353- let ports = [ self . reply0 . port_id ( ) , self . reply1 . port_id ( ) ] ;
354- bindings. insert :: < PortId > ( ports) ?;
355- Ok ( bindings)
308+ fn unbind ( & self , bindings : & mut Bindings ) -> anyhow:: Result < ( ) > {
309+ self . reply0 . unbind ( bindings) ?;
310+ self . reply1 . unbind ( bindings) ?;
311+ Ok ( ( ) )
356312 }
357313 }
358314
359315 // TODO(pzhang) add macro to auto-gen this implementation.
360316 impl Bind for MyMessage {
361- fn bind ( mut self , bindings : & Bindings ) -> anyhow:: Result < Self > {
362- let mut_ports = [ self . reply0 . port_id_mut ( ) , self . reply1 . port_id_mut ( ) ] ;
363- bindings . rebind :: < PortId > ( mut_ports . into_iter ( ) ) ?;
364- Ok ( self )
317+ fn bind ( & mut self , bindings : & mut Bindings ) -> anyhow:: Result < ( ) > {
318+ self . reply0 . bind ( bindings ) ? ;
319+ self . reply1 . bind ( bindings ) ?;
320+ Ok ( ( ) )
365321 }
366322 }
367323
@@ -384,12 +340,20 @@ mod tests {
384340 erased,
385341 ErasedUnbound {
386342 message: serialized_my_message. clone( ) ,
387- bindings: Bindings ( hashmap! {
388- PortId :: typehash( ) => vec![
389- Serialized :: serialize( original_port0. port_id( ) ) . unwrap( ) ,
390- Serialized :: serialize( original_port1. port_id( ) ) . unwrap( ) ,
391- ] ,
392- } ) ,
343+ bindings: Bindings (
344+ [
345+ (
346+ PortId :: typehash( ) ,
347+ Serialized :: serialize( original_port0. port_id( ) ) . unwrap( )
348+ ) ,
349+ (
350+ PortId :: typehash( ) ,
351+ Serialized :: serialize( original_port1. port_id( ) ) . unwrap( )
352+ ) ,
353+ ]
354+ . into_iter( )
355+ . collect( )
356+ ) ,
393357 }
394358 ) ;
395359
@@ -399,15 +363,27 @@ mod tests {
399363 let new_port_id1 = id ! ( world[ 1 ] . comm[ 0 ] [ 257 ] ) ;
400364 assert_ne ! ( & new_port_id1, original_port1. port_id( ) ) ;
401365
366+ let mut new_ports = vec ! [ & new_port_id0, & new_port_id1] . into_iter ( ) ;
402367 erased
403- . replace :: < PortId > ( vec ! [ & new_port_id0, & new_port_id1] . into_iter ( ) )
368+ . visit_mut :: < PortId > ( |p| {
369+ * p = new_ports. next ( ) . unwrap ( ) . clone ( ) ;
370+ Ok ( ( ) )
371+ } )
404372 . unwrap ( ) ;
405- let new_bindings = Bindings ( hashmap ! {
406- PortId :: typehash( ) => vec![
407- Serialized :: serialize( & new_port_id0) . unwrap( ) ,
408- Serialized :: serialize( & new_port_id1) . unwrap( ) ,
409- ] ,
410- } ) ;
373+ let new_bindings = Bindings (
374+ [
375+ (
376+ PortId :: typehash ( ) ,
377+ Serialized :: serialize ( & new_port_id0) . unwrap ( ) ,
378+ ) ,
379+ (
380+ PortId :: typehash ( ) ,
381+ Serialized :: serialize ( & new_port_id1) . unwrap ( ) ,
382+ ) ,
383+ ]
384+ . into_iter ( )
385+ . collect ( ) ,
386+ ) ;
411387 assert_eq ! (
412388 erased,
413389 ErasedUnbound {
0 commit comments