@@ -90,7 +90,18 @@ impl Iterator for PeersIter {
9090 }
9191}
9292
93- /// Get the peer cirresponding to the local device.
93+ /// Stash is a serialized binary state of the app that you want to persist
94+ /// between app runs and to be available in multiplayer.
95+ ///
96+ /// For single-player purposes, you can save data in a regular file
97+ /// using [`dump_file`](crate::dump_file). File saved that way can be bigger
98+ /// (and you can create lots of them) but it cannot be accessed in multiplayer.
99+ ///
100+ /// It's your job to serialize data into a binary stash and later parse it.
101+ /// Stash can be saved using [`save_stash`] and later read using [`load_stash`].
102+ type Stash = [ u8 ] ;
103+
104+ /// Get the peer corresponding to the local device.
94105#[ must_use]
95106pub fn get_me ( ) -> Peer {
96107 let me = unsafe { bindings:: get_me ( ) } ;
@@ -104,11 +115,71 @@ pub fn get_peers() -> Peers {
104115 Peers ( peers)
105116}
106117
118+ /// Save the given [`Stash`].
119+ ///
120+ /// When called, the stash for the given peer will be stored in RAM.
121+ /// Calling [`load_stash`] for the same peer will return that stash.
122+ /// On exit, the runtime will persist the stash in FS.
123+ /// Next time the app starts, calling [`load_stash`] will restore the stash
124+ /// saved earlier.
125+ pub fn save_stash ( peer : Peer , stash : & Stash ) {
126+ let ptr = stash. as_ptr ( ) ;
127+ let peer = u32:: from ( peer. 0 ) ;
128+ unsafe {
129+ bindings:: save_stash ( peer, ptr as u32 , stash. len ( ) as u32 ) ;
130+ }
131+ }
132+
133+ /// Read the stash of the given peer using the passed buffer.
134+ ///
135+ /// It's the app's responsibility to ensure that the passed buffer is big enough
136+ /// to fit the stash. If it doesn't fit, runtime will fill the buffer
137+ /// and discard the rest.
138+ ///
139+ /// The returned stash is a slice of the passed in buffer of the actual content size
140+ /// (up to the buffer size).
141+ ///
142+ /// If there is no stash (which is always true before [`save_stash`]
143+ /// is called for the first time ever), the result is `None`.
144+ #[ must_use]
145+ pub fn load_stash ( peer : Peer , stash : & mut Stash ) -> Option < & mut Stash > {
146+ let ptr = stash. as_ptr ( ) ;
147+ let peer = u32:: from ( peer. 0 ) ;
148+ let size = unsafe { bindings:: load_stash ( peer, ptr as u32 , stash. len ( ) as u32 ) } ;
149+ if size == 0 {
150+ return None ;
151+ }
152+ let size = size as usize ;
153+ Some ( & mut stash[ ..size] )
154+ }
155+
156+ /// Similar to [`load_stash`] but statically allocates the stash of the right size.
157+ ///
158+ /// Unlike [`load_stash`], the returned stash size is not adjusted
159+ /// for the actual content size.
160+ ///
161+ /// Unlike other `_buf` functions, like [`load_file_buf`][crate::load_file_buf],
162+ /// this one allocates the buffer statically, not dynamically.
163+ /// The app must statically know the max stash size.
164+ #[ must_use]
165+ pub fn load_stash_buf < const N : usize > ( peer : Peer ) -> Option < [ u8 ; N ] > {
166+ let stash = [ 0u8 ; N ] ;
167+ let ptr = stash. as_ptr ( ) ;
168+ let peer = u32:: from ( peer. 0 ) ;
169+ let size = unsafe { bindings:: load_stash ( peer, ptr as u32 , stash. len ( ) as u32 ) } ;
170+ if size == 0 {
171+ return None ;
172+ }
173+ Some ( stash)
174+ }
175+
107176/// Internal bindings to the raw runtime functions.
108177mod bindings {
109178 #[ link( wasm_import_module = "net" ) ]
110179 extern {
111180 pub ( crate ) fn get_me ( ) -> u32 ;
112181 pub ( crate ) fn get_peers ( ) -> u32 ;
182+ pub ( crate ) fn save_stash ( peer : u32 , ptr : u32 , len : u32 ) ;
183+ pub ( crate ) fn load_stash ( peer : u32 , ptr : u32 , len : u32 ) -> u32 ;
113184 }
114185}
0 commit comments