stardust_xr_fusion/
root.rs

1use crate::client::ClientHandle;
2use crate::spatial::{SpatialRef, SpatialRefAspect};
3use rustc_hash::FxHashMap;
4use serde::Serialize;
5use serde::de::DeserializeOwned;
6use stardust_xr::schemas::flex::flexbuffers::{self, SerializationError};
7use std::sync::Arc;
8
9pub use crate::protocol::root::*;
10
11/// The persistent state of a Stardust client.
12impl Default for ClientState {
13	fn default() -> Self {
14		ClientState {
15			data: None,
16			root: 0,
17			spatial_anchors: Default::default(),
18		}
19	}
20}
21impl ClientState {
22	pub fn new<T: Serialize>(
23		data: Option<T>,
24		root: &impl SpatialRefAspect,
25		spatial_anchors: FxHashMap<String, &impl SpatialRefAspect>,
26	) -> Result<Self, SerializationError> {
27		Ok(ClientState {
28			data: data.map(flexbuffers::to_vec).transpose()?,
29			root: root.id(),
30			spatial_anchors: spatial_anchors
31				.into_iter()
32				.map(|(k, v)| (k, v.id()))
33				.collect(),
34		})
35	}
36	pub fn from_data_root<T: Serialize>(
37		data: Option<T>,
38		root: &impl SpatialRefAspect,
39	) -> Result<Self, SerializationError> {
40		Self::new(data, root, FxHashMap::<String, &SpatialRef>::default())
41	}
42	pub fn from_root_anchors(
43		root: &impl SpatialRefAspect,
44		spatial_anchors: FxHashMap<String, &impl SpatialRefAspect>,
45	) -> Result<Self, SerializationError> {
46		Self::new(None::<()>, root, spatial_anchors)
47	}
48	pub fn from_root(root: &impl SpatialRefAspect) -> Result<Self, SerializationError> {
49		Self::from_data_root(None::<()>, root)
50	}
51
52	pub fn data<T: DeserializeOwned>(&self) -> Option<T> {
53		flexbuffers::from_buffer(&self.data.as_ref()?.as_slice()).ok()
54	}
55	pub fn root(&self, client: &Arc<ClientHandle>) -> SpatialRef {
56		SpatialRef::from_id(client, self.root, false)
57	}
58	pub fn spatial_anchors(&self, client: &Arc<ClientHandle>) -> FxHashMap<String, SpatialRef> {
59		self.spatial_anchors
60			.iter()
61			.map(|(k, v)| (k.to_string(), SpatialRef::from_id(client, *v, false)))
62			.collect()
63	}
64}
65
66#[tokio::test]
67async fn fusion_root_save_state() {
68	use crate::Client;
69	let mut client = Client::connect().await.expect("Couldn't connect");
70	client
71		.sync_event_loop(|client, flow| {
72			let root = client.get_root();
73			while let Some(event) = root.recv_root_event() {
74				match event {
75					RootEvent::Ping { response } => response.send_ok(()),
76					RootEvent::Frame { info: _ } => (),
77					RootEvent::SaveState { response } => {
78						response.send(ClientState::from_data_root(Some(()), root));
79						flow.stop();
80					}
81				}
82			}
83		})
84		.await
85		.unwrap();
86}