Skip to content

Commit 638c408

Browse files
authored
Merge pull request #15 from firefly-zero/stash
Add stash functions
2 parents 8d700c7 + e52d6c3 commit 638c408

File tree

1 file changed

+72
-1
lines changed

1 file changed

+72
-1
lines changed

src/net.rs

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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]
95106
pub 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.
108177
mod 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

Comments
 (0)