diff --git a/fusion/Cargo.toml b/fusion/Cargo.toml index 45aa199..0e103b9 100644 --- a/fusion/Cargo.toml +++ b/fusion/Cargo.toml @@ -2,9 +2,9 @@ edition = "2024" rust-version = "1.85" name = "stardust-xr-fusion" -version.workspace = true authors = ["Nova King "] description = "High level client library for the Stardust XR display server" +version.workspace = true license.workspace = true repository.workspace = true homepage.workspace = true @@ -37,14 +37,13 @@ zbus = { version = "5.11.0", features = [ "tokio", ], default-features = false } stardust-xr-wire = { version = "0.50.0", path = "../wire" } -stardust-xr-gluon = { version = "2.0.0", path = "../gluon" } +stardust-xr-gluon = { version = "0.50.0", path = "../gluon" } [build-dependencies] convert_case = "0.8.0" quote = "1.0.33" -stardust-xr-protocol = { version = "2.0.0", path = "../protocol" } +stardust-xr-protocol = { version = "0.50.0", path = "../protocol" } proc-macro2 = "1.0.71" -clap = { version = "4.4", features = ["derive"] } color-eyre = "0.6" syn = "2.0.106" prettyplease = "0.2.37" diff --git a/fusion/build.rs b/fusion/build.rs index 050deae..5eaeeeb 100644 --- a/fusion/build.rs +++ b/fusion/build.rs @@ -3,10 +3,14 @@ use convert_case::{Case, Casing}; use proc_macro2::{Ident, Span, TokenStream}; use quote::{ToTokens, quote}; use stardust_xr_protocol::*; +use std::collections::HashMap; use std::env; use std::fs; use std::path::Path; use std::path::PathBuf; +use std::sync::LazyLock; +use std::sync::Mutex; + fn main() { // Watch for changes to KDL schema files let schema_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()) @@ -106,6 +110,48 @@ pub fn get_all_protocols() -> Vec { ] } +static CLONE_PARTIAL_EQ_CACHE: LazyLock>> = + LazyLock::new(Default::default); +fn can_impl_clone_and_partial_eq(arg: &ArgumentType) -> bool { + match &arg { + ArgumentType::Union(name) => *CLONE_PARTIAL_EQ_CACHE.lock().unwrap().get(name).unwrap(), + ArgumentType::Struct(name) => *CLONE_PARTIAL_EQ_CACHE.lock().unwrap().get(name).unwrap(), + ArgumentType::Fd => false, + _ => true, + } +} +fn setup_impl_clone_and_partial_eq(protocol_definitions: &[&Protocol], arg: &ArgumentType) -> bool { + match &arg { + ArgumentType::Union(name) | ArgumentType::Struct(name) => { + if let Some(v) = CLONE_PARTIAL_EQ_CACHE.lock().unwrap().get(name) { + return *v; + }; + let v = protocol_definitions + .iter() + .flat_map(|v| v.custom_unions.iter()) + .filter(|v| &v.name == name) + .flat_map(|v| v.options.iter()) + .map(|v| &v._type) + .chain( + protocol_definitions + .iter() + .flat_map(|v| v.custom_structs.iter()) + .filter(|v| &v.name == name) + .flat_map(|v| v.fields.iter()) + .map(|v| &v._type), + ) + .all(|v| setup_impl_clone_and_partial_eq(protocol_definitions, v)); + CLONE_PARTIAL_EQ_CACHE + .lock() + .unwrap() + .insert(name.clone(), v); + v + } + ArgumentType::Fd => false, + _ => true, + } +} + pub fn generate_protocol_file( protocols: Vec, file_path: &Path, @@ -118,6 +164,25 @@ pub fn generate_protocol_file( let mut protocol_definitions = protocols.iter_mut().map(|(p, _)| p).collect::>(); stardust_xr_protocol::resolve_inherits(&mut protocol_definitions).unwrap(); + let protocol_definitions = protocols.iter().map(|(p, _)| p).collect::>(); + protocol_definitions + .iter() + .flat_map(|v| v.custom_structs.iter()) + .for_each(|v| { + setup_impl_clone_and_partial_eq( + &protocol_definitions, + &ArgumentType::Struct(v.name.clone()), + ); + }); + protocol_definitions + .iter() + .flat_map(|v| v.custom_unions.iter()) + .for_each(|v| { + setup_impl_clone_and_partial_eq( + &protocol_definitions, + &ArgumentType::Union(v.name.clone()), + ); + }); // panic!("{protocol_definitions:# ?}"); @@ -258,10 +323,19 @@ impl Tokenize for CustomUnion { .iter() .map(|e| e.tokenize(_generate_node, partial_eq)); - let derive = if partial_eq { - quote!( #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] ) - } else { - quote!( #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] ) + let derive = match ( + partial_eq, + can_impl_clone_and_partial_eq(&ArgumentType::Enum(self.name.clone())), + ) { + (true, true) => { + quote!( #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] ) + } + (false, true) => { + quote!( #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] ) + } + (_, false) => { + quote!( #[derive(Debug, serde::Deserialize, serde::Serialize)] ) + } }; quote! { #[doc = #description] @@ -322,16 +396,21 @@ impl Tokenize for CustomStruct { let name = Ident::new(&self.name.to_case(Case::Pascal), Span::call_site()); let description = &self.description; - let argument_decls = self - .fields - .iter() - .map(|a| generate_argument_decl(a, true)) - .map(|d| quote!(pub #d)); + let argument_decls = self.fields.iter().map(|a| generate_pub_field_decl(a, true)); - let derive = if partial_eq { - quote!( #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] ) - } else { - quote!( #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] ) + let derive = match ( + partial_eq, + can_impl_clone_and_partial_eq(&ArgumentType::Struct(self.name.clone())), + ) { + (true, true) => { + quote!( #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] ) + } + (false, true) => { + quote!( #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] ) + } + (_, false) => { + quote!( #[derive(Debug, serde::Deserialize, serde::Serialize)] ) + } }; quote! { #[doc = #description] @@ -643,7 +722,7 @@ fn generate_event_sender_impl(aspect: &Aspect) -> TokenStream { member._type, quote! { #opcode => { - let (#(#field_names),*): (#(#deserialize_types),*) = stardust_xr_wire::flex::deserialize(_data)?; + let (#(#field_names),*): (#(#deserialize_types),*) = stardust_xr_wire::flex::deserialize(_data, _fds)?; #debug Ok(#event_name::#variant_name { #(#field_uses,)* #response_sender }) @@ -732,19 +811,17 @@ fn generate_server_member( MemberType::Signal => { let mut body = if let Some(interface_node_id) = &interface_node_id { quote! { - let mut _fds = Vec::new(); let data = (#(#argument_uses),*); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; - _client.message_sender_handle.signal(#interface_node_id, #aspect_id, #opcode, &serialized_data, _fds)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; + _client.message_sender_handle.signal(#interface_node_id, #aspect_id, #opcode, &serialized_data, fds)?; let (#(#arguments),*) = data; tracing::trace!(#arguments_debug "Sent signal to server, {}::{}", #aspect_name, #name_str); } } else { quote! { - let mut _fds = Vec::new(); let data = (#(#argument_uses),*); - self.node().send_signal(#aspect_id, #opcode, &data, _fds)?; + self.node().send_signal(#aspect_id, #opcode, &data)?; let (#(#arguments),*) = data; tracing::trace!(#arguments_debug "Sent signal to server, {}::{}", #aspect_name, #name_str); @@ -795,28 +872,26 @@ fn generate_server_member( let deserialize = generate_argument_deserialize("result", &argument_type, false); let body = if let Some(interface_node_id) = &interface_node_id { quote! { - let mut _fds = Vec::new(); let data = (#(#argument_uses),*); { let (#(#arguments),*) = &data; tracing::trace!(#arguments_debug "Called method on server, {}::{}", #aspect_name, #name_str); } - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; - let message = _client.message_sender_handle.method(#interface_node_id, #aspect_id, #opcode, &serialized_data, _fds).await?.map_err(|e| crate::node::NodeError::ReturnedError { e })?.into_message(); - let result: #deserializeable_type = stardust_xr_wire::flex::deserialize(&message)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; + let (message, message_fds) = _client.message_sender_handle.method(#interface_node_id, #aspect_id, #opcode, &serialized_data, fds).await?.map_err(|e| crate::node::NodeError::ReturnedError { e })?.into_components(); + let result: #deserializeable_type = stardust_xr_wire::flex::deserialize(&message, message_fds)?; let deserialized = #deserialize; tracing::trace!("return" = ?deserialized, "Method return from server, {}::{}", #aspect_name, #name_str); Ok(deserialized) } } else { quote! {{ - let mut _fds = Vec::new(); let data = (#(#argument_uses),*); { let (#(#arguments),*) = &data; tracing::trace!(#arguments_debug "Called method on server, {}::{}", #aspect_name, #name_str); } - let result: #deserializeable_type = self.node().call_method(#aspect_id, #opcode, &data, _fds).await?; + let result: #deserializeable_type = self.node().call_method(#aspect_id, #opcode, &data).await?; let deserialized = #deserialize; tracing::trace!("return" = ?deserialized, "Method return from server, {}::{}", #aspect_name, #name_str); Ok(deserialized) @@ -869,9 +944,6 @@ fn generate_argument_deserialize( let mapping = generate_argument_deserialize("a", v, false); quote!(#name.into_iter().map(|(k, a)| Ok((k, #mapping))).collect::, crate::node::NodeError>>()?) } - ArgumentType::Fd => { - quote!(_fds.remove(0)) - } _ => quote!(#name), } } @@ -928,12 +1000,6 @@ fn generate_argument_serialize( let mapping = generate_argument_serialize("a", v, false); quote!(#name.iter().map(|(k, a)| Ok((k, #mapping))).collect::>>()?) } - ArgumentType::Fd => { - quote!({ - _fds.push(#name); - (_fds.len() - 1) as u32 - }) - } _ => quote!(#name), } } @@ -945,6 +1011,19 @@ fn generate_argument_decl(argument: &Argument, returned: bool) -> TokenStream { } quote!(#name: #_type) } +fn generate_pub_field_decl(argument: &Argument, returned: bool) -> TokenStream { + let name = Ident::new(&argument.name.to_case(Case::Snake), Span::call_site()); + let mut _type = generate_argument_type(&argument._type, returned); + if argument.optional { + _type = quote!(Option<#_type>); + } + let description = argument + .description + .as_ref() + .map(|d| quote!(#[doc = #d])) + .unwrap_or_default(); + quote!(#description pub #name: #_type) +} fn generate_argument_type(argument_type: &ArgumentType, owned: bool) -> TokenStream { match argument_type { ArgumentType::Empty => quote!(()), @@ -1057,7 +1136,7 @@ fn generate_argument_type(argument_type: &ArgumentType, owned: bool) -> TokenStr } } ArgumentType::Fd => { - quote!(std::os::unix::io::OwnedFd) + quote!(stardust_xr_wire::fd::ProtocolFd) } } } diff --git a/fusion/src/lib.rs b/fusion/src/lib.rs index 0f287ea..805fa50 100644 --- a/fusion/src/lib.rs +++ b/fusion/src/lib.rs @@ -5,7 +5,7 @@ use serde::Serialize; use stardust_xr_wire::{flex::serialize, messenger::MethodResponse, scenegraph::ScenegraphError}; -use std::{error::Error, fmt::Debug, marker::PhantomData, os::fd::OwnedFd}; +use std::{error::Error, fmt::Debug, marker::PhantomData}; pub use client::*; pub use stardust_xr_gluon::*; @@ -44,23 +44,20 @@ impl TypedMethodResponse { return; } }; - let Ok(serialized) = stardust_xr_wire::flex::serialize(data) else { + let Ok((serialized, fds)) = stardust_xr_wire::flex::serialize(data) else { self.0.send(Err(ScenegraphError::MemberError { error: "Internal: Failed to serialize".to_string(), })); return; }; - self.0.send(Ok((&serialized, Vec::::new()))); + self.0.send(Ok((&serialized, fds))); } pub fn wrap Result>(self, f: F) { self.send(f()) } - pub fn wrap_async( - self, - f: impl Future), E>> + Send + 'static, - ) { + pub fn wrap_async(self, f: impl Future> + Send + 'static) { tokio::task::spawn(async move { - let (value, fds) = match f.await { + let value = match f.await { Ok(d) => d, Err(e) => { self.0.send(Err(ScenegraphError::MemberError { @@ -69,7 +66,7 @@ impl TypedMethodResponse { return; } }; - let Ok(serialized) = serialize(value) else { + let Ok((serialized, fds)) = serialize(value) else { self.0.send(Err(ScenegraphError::MemberError { error: "Internal: Failed to serialize".to_string(), })); diff --git a/fusion/src/node.rs b/fusion/src/node.rs index 623a429..2833b1c 100644 --- a/fusion/src/node.rs +++ b/fusion/src/node.rs @@ -7,7 +7,7 @@ use stardust_xr_wire::{ messenger::MessengerError, scenegraph::ScenegraphError, }; -use std::{fmt::Debug, os::fd::OwnedFd, sync::Arc, vec::Vec}; +use std::{fmt::Debug, sync::Arc}; use thiserror::Error; pub use crate::protocol::node::*; @@ -106,9 +106,8 @@ impl NodeCore { aspect: u64, signal: u64, data: &S, - fds: Vec, ) -> Result<(), NodeError> { - let serialized = serialize(data).map_err(|e| NodeError::Serialization { e })?; + let (serialized, fds) = serialize(data).map_err(|e| NodeError::Serialization { e })?; self.client .message_sender_handle .signal(self.id, aspect, signal, &serialized, fds) @@ -124,9 +123,8 @@ impl NodeCore { aspect: u64, method: u64, data: &S, - fds: Vec, ) -> Result { - let serialized = serialize(data).map_err(|e| NodeError::Serialization { e })?; + let (serialized, fds) = serialize(data).map_err(|e| NodeError::Serialization { e })?; let response = self .client @@ -139,7 +137,8 @@ impl NodeCore { })? .map_err(|e| NodeError::ReturnedError { e })?; - deserialize(&response.into_message()).map_err(|e| NodeError::Deserialization { e }) + let (response, fds) = response.into_components(); + deserialize(&response, fds).map_err(|e| NodeError::Deserialization { e }) } } impl NodeType for NodeCore { diff --git a/fusion/src/protocol.rs b/fusion/src/protocol.rs index ce58034..43a9f48 100644 --- a/fusion/src/protocol.rs +++ b/fusion/src/protocol.rs @@ -16,14 +16,19 @@ pub mod root { /// #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] pub struct FrameInfo { + ///The time between this frame and last frame's display time, in seconds. pub delta: f32, + ///The total time in seconds the client has been connected to the server. pub elapsed: f32, } ///The persistent state of a Stardust client. #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] pub struct ClientState { + ///Data specific to your client, put anything you like here and it'll be saved/restored intact. pub data: Option>, + ///Where the client's root should be positioned on reload. pub root: u64, + ///Spatials that will be in the same place you left them. pub spatial_anchors: stardust_xr_wire::values::Map, } ///The hub of the client. Spatially this is positioned where the client is started so is a stable base to position things relative to. @@ -102,6 +107,7 @@ pub mod root { 2586777469268117179u64 => { let (info): (FrameInfo) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? info, "Got signal from server, {}::{}", "Root", "frame" @@ -120,7 +126,7 @@ pub mod root { ) -> Result { match method_id { 1374738518356883234u64 => { - let (): () = stardust_xr_wire::flex::deserialize(_data)?; + let (): () = stardust_xr_wire::flex::deserialize(_data, _fds)?; tracing::trace!("Method called from server, {}::{}", "Root", "ping"); Ok(RootEvent::Ping { response: crate::TypedMethodResponse( @@ -130,7 +136,7 @@ pub mod root { }) } 6559167809188075643u64 => { - let (): () = stardust_xr_wire::flex::deserialize(_data)?; + let (): () = stardust_xr_wire::flex::deserialize(_data, _fds)?; tracing::trace!( "Method called from server, {}::{}", "Root", "save_state" ); @@ -159,7 +165,6 @@ pub mod root { ///Get the current state. Useful to check the state before you initialize your application! async fn get_state(&self) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (); { let () = &data; @@ -169,12 +174,7 @@ pub mod root { } let result: ClientState = self .node() - .call_method( - 7212020743076450030u64, - 14958324855167218950u64, - &data, - _fds, - ) + .call_method(7212020743076450030u64, 14958324855167218950u64, &data) .await?; let deserialized = result; tracing::trace!( @@ -195,7 +195,6 @@ pub mod root { state: ClientState, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (state); { let (state) = &data; @@ -206,12 +205,7 @@ pub mod root { } let result: String = self .node() - .call_method( - 7212020743076450030u64, - 530863980839400599u64, - &data, - _fds, - ) + .call_method(7212020743076450030u64, 530863980839400599u64, &data) .await?; let deserialized = result; tracing::trace!( @@ -226,7 +220,6 @@ pub mod root { &self, ) -> crate::node::NodeResult> { { - let mut _fds = Vec::new(); let data = (); { let () = &data; @@ -237,12 +230,7 @@ pub mod root { } let result: stardust_xr_wire::values::Map = self .node() - .call_method( - 7212020743076450030u64, - 3344613215577382567u64, - &data, - _fds, - ) + .call_method(7212020743076450030u64, 3344613215577382567u64, &data) .await?; let deserialized = result .into_iter() @@ -262,18 +250,12 @@ pub mod root { } ///Set initial list of folders to look for namespaced resources in fn set_base_prefixes(&self, prefixes: &[String]) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (prefixes .iter() .map(|a| Ok(a)) .collect::>>()?); self.node() - .send_signal( - 7212020743076450030u64, - 3714507829296596139u64, - &data, - _fds, - )?; + .send_signal(7212020743076450030u64, 3714507829296596139u64, &data)?; let (prefixes) = data; tracing::trace!( ? prefixes, "Sent signal to server, {}::{}", "Root", "set_base_prefixes" @@ -282,15 +264,9 @@ pub mod root { } ///Cleanly disconnect from the server fn disconnect(&self) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (); self.node() - .send_signal( - 7212020743076450030u64, - 662137628972844924u64, - &data, - _fds, - )?; + .send_signal(7212020743076450030u64, 662137628972844924u64, &data)?; let () = data; tracing::trace!("Sent signal to server, {}::{}", "Root", "disconnect"); Ok(()) @@ -309,15 +285,9 @@ pub mod node { pub trait OwnedAspect: crate::node::NodeType + std::fmt::Debug { ///Set if this node is enabled or not. Disabled drawables won't render, input handlers won't receive input, etc. fn set_enabled(&self, enabled: bool) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (enabled); self.node() - .send_signal( - 15801764205032075891u64, - 13365497663235993822u64, - &data, - _fds, - )?; + .send_signal(15801764205032075891u64, 13365497663235993822u64, &data)?; let (enabled) = data; tracing::trace!( ? enabled, "Sent signal to server, {}::{}", "Owned", "set_enabled" @@ -326,15 +296,9 @@ pub mod node { } ///Destroy this node immediately. Not all nodes will have this method, those that don't can be dropped client-side without issue. fn destroy(&self) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (); self.node() - .send_signal( - 15801764205032075891u64, - 8637450960623370830u64, - &data, - _fds, - )?; + .send_signal(15801764205032075891u64, 8637450960623370830u64, &data)?; let () = data; tracing::trace!("Sent signal to server, {}::{}", "Owned", "destroy"); Ok(()) @@ -418,7 +382,6 @@ pub mod spatial { ///Get the bounding box of this spatial and its children relative to another spatial async fn get_local_bounding_box(&self) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (); { let () = &data; @@ -429,12 +392,7 @@ pub mod spatial { } let result: BoundingBox = self .node() - .call_method( - 14774096707642646617u64, - 15184457389419466387u64, - &data, - _fds, - ) + .call_method(14774096707642646617u64, 15184457389419466387u64, &data) .await?; let deserialized = result; tracing::trace!( @@ -450,7 +408,6 @@ pub mod spatial { relative_to: &impl SpatialRefAspect, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (relative_to.node().id); { let (relative_to) = &data; @@ -461,12 +418,7 @@ pub mod spatial { } let result: BoundingBox = self .node() - .call_method( - 14774096707642646617u64, - 8077745023404307052u64, - &data, - _fds, - ) + .call_method(14774096707642646617u64, 8077745023404307052u64, &data) .await?; let deserialized = result; tracing::trace!( @@ -482,7 +434,6 @@ pub mod spatial { relative_to: &impl SpatialRefAspect, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (relative_to.node().id); { let (relative_to) = &data; @@ -493,12 +444,7 @@ pub mod spatial { } let result: Transform = self .node() - .call_method( - 14774096707642646617u64, - 6982810219028106561u64, - &data, - _fds, - ) + .call_method(14774096707642646617u64, 6982810219028106561u64, &data) .await?; let deserialized = result; tracing::trace!( @@ -575,15 +521,9 @@ pub mod spatial { &self, transform: Transform, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (transform); self.node() - .send_signal( - 17785849468685298036u64, - 5092462149256736585u64, - &data, - _fds, - )?; + .send_signal(17785849468685298036u64, 5092462149256736585u64, &data)?; let (transform) = data; tracing::trace!( ? transform, "Sent signal to server, {}::{}", "Spatial", @@ -597,15 +537,9 @@ pub mod spatial { relative_to: &impl SpatialRefAspect, transform: Transform, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (relative_to.node().id, transform); self.node() - .send_signal( - 17785849468685298036u64, - 15020422542376308840u64, - &data, - _fds, - )?; + .send_signal(17785849468685298036u64, 15020422542376308840u64, &data)?; let (relative_to, transform) = data; tracing::trace!( ? relative_to, ? transform, "Sent signal to server, {}::{}", "Spatial", @@ -621,15 +555,9 @@ pub mod spatial { &self, parent: &impl SpatialRefAspect, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (parent.node().id); self.node() - .send_signal( - 17785849468685298036u64, - 12472379656662040034u64, - &data, - _fds, - )?; + .send_signal(17785849468685298036u64, 12472379656662040034u64, &data)?; let (parent) = data; tracing::trace!( ? parent, "Sent signal to server, {}::{}", "Spatial", @@ -645,15 +573,9 @@ pub mod spatial { &self, parent: &impl SpatialRefAspect, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (parent.node().id); self.node() - .send_signal( - 17785849468685298036u64, - 1386737540675144626u64, - &data, - _fds, - )?; + .send_signal(17785849468685298036u64, 1386737540675144626u64, &data)?; let (parent) = data; tracing::trace!( ? parent, "Sent signal to server, {}::{}", "Spatial", @@ -664,7 +586,6 @@ pub mod spatial { ///Return a UUID representing this node's SpatialRef that you can send to other clients async fn export_spatial(&self) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (); { let () = &data; @@ -674,12 +595,7 @@ pub mod spatial { } let result: u64 = self .node() - .call_method( - 17785849468685298036u64, - 3600225297814947977u64, - &data, - _fds, - ) + .call_method(17785849468685298036u64, 3600225297814947977u64, &data) .await?; let deserialized = result; tracing::trace!( @@ -695,7 +611,6 @@ pub mod spatial { _client: &std::sync::Arc, uid: u64, ) -> crate::node::NodeResult { - let mut _fds = Vec::new(); let data = (uid); { let (uid) = &data; @@ -704,16 +619,16 @@ pub mod spatial { "import_spatial_ref" ); } - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; - let message = _client + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; + let (message, message_fds) = _client .message_sender_handle - .method(1u64, 0u64, 7309812661610962094u64, &serialized_data, _fds) + .method(1u64, 0u64, 7309812661610962094u64, &serialized_data, fds) .await? .map_err(|e| crate::node::NodeError::ReturnedError { e, })? - .into_message(); - let result: u64 = stardust_xr_wire::flex::deserialize(&message)?; + .into_components(); + let result: u64 = stardust_xr_wire::flex::deserialize(&message, message_fds)?; let deserialized = SpatialRef::from_id(_client, result, false); tracing::trace!( "return" = ? deserialized, "Method return from server, {}::{}", "Interface", @@ -729,12 +644,11 @@ pub mod spatial { transform: Transform, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (id, parent.node().id, transform); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(1u64, 0u64, 3949276749019911643u64, &serialized_data, _fds)?; + .signal(1u64, 0u64, 3949276749019911643u64, &serialized_data, fds)?; let (id, parent, transform) = data; tracing::trace!( ? id, ? parent, ? transform, "Sent signal to server, {}::{}", @@ -767,23 +681,33 @@ pub mod field { ///Information about raymarching a field. All vectors are relative to the spatial reference used. #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] pub struct RayMarchResult { + ///Origin of the ray pub ray_origin: stardust_xr_wire::values::Vector3, + ///Direction of the ray pub ray_direction: stardust_xr_wire::values::Vector3, + ///How close to or far inside the field the ray got. If less than zero, the ray intersected the field. pub min_distance: f32, + ///The distance to the point on the ray that has the least distance to the field/most distance inside it. Useful for finding a "near miss" point or how close to the core of the field you're pointing. pub deepest_point_distance: f32, + ///Maximum length of the ray pub ray_length: f32, + ///Number of steps taken pub ray_steps: u32, } ///Cylinder shape info #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] pub struct CylinderShape { + ///Length of the cylinder along the Y axis pub length: f32, + ///Radius of the cylinder along the XZ plane pub radius: f32, } ///Torus shape info #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] pub struct TorusShape { + ///Radius of the ring along the XZ plane pub radius_a: f32, + ///Radius of the tube pub radius_b: f32, } ///A reference to a signed distance field that you can sample @@ -845,7 +769,6 @@ pub mod field { point: impl Into>, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (space.node().id, point.into()); { let (space, point) = &data; @@ -856,12 +779,7 @@ pub mod field { } let result: f32 = self .node() - .call_method( - 10662923473076663509u64, - 12706699825100237095u64, - &data, - _fds, - ) + .call_method(10662923473076663509u64, 12706699825100237095u64, &data) .await?; let deserialized = result; tracing::trace!( @@ -878,7 +796,6 @@ pub mod field { point: impl Into>, ) -> crate::node::NodeResult> { { - let mut _fds = Vec::new(); let data = (space.node().id, point.into()); { let (space, point) = &data; @@ -889,12 +806,7 @@ pub mod field { } let result: stardust_xr_wire::values::Vector3 = self .node() - .call_method( - 10662923473076663509u64, - 10933809934326220183u64, - &data, - _fds, - ) + .call_method(10662923473076663509u64, 10933809934326220183u64, &data) .await?; let deserialized = result; tracing::trace!( @@ -911,7 +823,6 @@ pub mod field { point: impl Into>, ) -> crate::node::NodeResult> { { - let mut _fds = Vec::new(); let data = (space.node().id, point.into()); { let (space, point) = &data; @@ -922,12 +833,7 @@ pub mod field { } let result: stardust_xr_wire::values::Vector3 = self .node() - .call_method( - 10662923473076663509u64, - 13473947755141124846u64, - &data, - _fds, - ) + .call_method(10662923473076663509u64, 13473947755141124846u64, &data) .await?; let deserialized = result; tracing::trace!( @@ -945,7 +851,6 @@ pub mod field { ray_direction: impl Into>, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (space.node().id, ray_origin.into(), ray_direction.into()); { let (space, ray_origin, ray_direction) = &data; @@ -956,12 +861,7 @@ pub mod field { } let result: RayMarchResult = self .node() - .call_method( - 10662923473076663509u64, - 7352457860499612292u64, - &data, - _fds, - ) + .call_method(10662923473076663509u64, 7352457860499612292u64, &data) .await?; let deserialized = result; tracing::trace!( @@ -1035,15 +935,9 @@ pub mod field { pub trait FieldAspect: crate::node::NodeType + super::FieldRefAspect + super::SpatialRefAspect + super::SpatialAspect + super::OwnedAspect + std::fmt::Debug { ///Set the shape of this field (and its parameters) fn set_shape(&self, shape: Shape) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (shape); self.node() - .send_signal( - 3948434400034960392u64, - 10076774457453995458u64, - &data, - _fds, - )?; + .send_signal(3948434400034960392u64, 10076774457453995458u64, &data)?; let (shape) = data; tracing::trace!( ? shape, "Sent signal to server, {}::{}", "Field", "set_shape" @@ -1053,7 +947,6 @@ pub mod field { ///Return a UUID representing this node's FieldRef that you can send to other clients async fn export_field(&self) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (); { let () = &data; @@ -1063,12 +956,7 @@ pub mod field { } let result: u64 = self .node() - .call_method( - 3948434400034960392u64, - 939650650519133349u64, - &data, - _fds, - ) + .call_method(3948434400034960392u64, 939650650519133349u64, &data) .await?; let deserialized = result; tracing::trace!( @@ -1084,7 +972,6 @@ pub mod field { _client: &std::sync::Arc, uid: u64, ) -> crate::node::NodeResult { - let mut _fds = Vec::new(); let data = (uid); { let (uid) = &data; @@ -1092,16 +979,16 @@ pub mod field { ? uid, "Called method on server, {}::{}", "Interface", "import_field_ref" ); } - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; - let message = _client + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; + let (message, message_fds) = _client .message_sender_handle - .method(2u64, 0u64, 5844955584634021418u64, &serialized_data, _fds) + .method(2u64, 0u64, 5844955584634021418u64, &serialized_data, fds) .await? .map_err(|e| crate::node::NodeError::ReturnedError { e, })? - .into_message(); - let result: u64 = stardust_xr_wire::flex::deserialize(&message)?; + .into_components(); + let result: u64 = stardust_xr_wire::flex::deserialize(&message, message_fds)?; let deserialized = FieldRef::from_id(_client, result, false); tracing::trace!( "return" = ? deserialized, "Method return from server, {}::{}", "Interface", @@ -1118,12 +1005,11 @@ pub mod field { shape: Shape, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (id, parent.node().id, transform, shape); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(2u64, 0u64, 3216373392735127623u64, &serialized_data, _fds)?; + .signal(2u64, 0u64, 3216373392735127623u64, &serialized_data, fds)?; let (id, parent, transform, shape) = data; tracing::trace!( ? id, ? parent, ? transform, ? shape, "Sent signal to server, {}::{}", @@ -1199,30 +1085,18 @@ pub mod audio { pub trait SoundAspect: crate::node::NodeType + super::SpatialAspect + super::OwnedAspect + super::SpatialRefAspect + std::fmt::Debug { ///Play sound effect fn play(&self) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (); self.node() - .send_signal( - 17761155925539609649u64, - 18267594382511242772u64, - &data, - _fds, - )?; + .send_signal(17761155925539609649u64, 18267594382511242772u64, &data)?; let () = data; tracing::trace!("Sent signal to server, {}::{}", "Sound", "play"); Ok(()) } ///Stop sound effect fn stop(&self) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (); self.node() - .send_signal( - 17761155925539609649u64, - 4968801543080236686u64, - &data, - _fds, - )?; + .send_signal(17761155925539609649u64, 4968801543080236686u64, &data)?; let () = data; tracing::trace!("Sent signal to server, {}::{}", "Sound", "stop"); Ok(()) @@ -1237,12 +1111,11 @@ pub mod audio { resource: &stardust_xr_wire::values::ResourceID, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (id, parent.node().id, transform, resource); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(10u64, 0u64, 3197851813257440734u64, &serialized_data, _fds)?; + .signal(10u64, 0u64, 3197851813257440734u64, &serialized_data, fds)?; let (id, parent, transform, resource) = data; tracing::trace!( ? id, ? parent, ? transform, ? resource, "Sent signal to server, {}::{}", @@ -1309,6 +1182,14 @@ pub mod drawable { Exact, Overflow, } + ///Size and Dimensions of a Dmatex + #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] + #[serde(tag = "t", content = "c")] + pub enum DmatexSize { + Dim1D(u32), + Dim2D(stardust_xr_wire::values::Vector2), + Dim3D(stardust_xr_wire::values::Vector3), + } /// #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] #[serde(tag = "t", content = "c")] @@ -1321,20 +1202,60 @@ pub mod drawable { Vec3(stardust_xr_wire::values::Vector3), Color(stardust_xr_wire::values::Color), Texture(stardust_xr_wire::values::ResourceID), + ///only accepts 2d Dmatexs without array layers + Dmatex(DmatexMaterialParam), + } + ///Description of a format supported by the server + #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] + pub struct DmatexFormatInfo { + ///drm_fourcc for the format + pub format: u32, + pub drm_modifier: u64, + pub is_srgb: bool, + ///How many memory planes does this format use + pub planes: u32, + } + ///A single memory plane of a Dmatex + #[derive(Debug, serde::Deserialize, serde::Serialize)] + pub struct DmatexPlane { + ///the underlying dmabuf fd for this plane + pub dmabuf_fd: stardust_xr_wire::fd::ProtocolFd, + ///offset of the data relevant to this Dmatex plane in the Dmatex memory + pub offset: u32, + ///the number of bytes between the beginning of one pixel row to the next, if the Dmatex is 1d this should be 0 + pub row_size: u32, + ///the number of bytes between the beginning of one array element to the next, if the Dmatex is not an array texture this should be 0 + pub array_element_size: u32, + ///the number of bytes between the beginning of one 3d slice to the next, if the Dmatex is not 3d this should be 0 + pub depth_slice_size: u32, } ///A single point on a line #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] pub struct LinePoint { + ///The position of the point relative to the Lines node pub point: stardust_xr_wire::values::Vector3, + ///Thickness in meters, world space pub thickness: f32, + ///Color of the point, premultiplied alpha pub color: stardust_xr_wire::values::Color, } ///A single continuous polyline #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] pub struct Line { pub points: Vec, + ///Cyclic if first point connects to the last point pub cyclic: bool, } + ///Dmatex Material Parameter info + #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] + pub struct DmatexMaterialParam { + ///The id of the Dmatex to be applied as the texture + pub dmatex_id: u64, + ///the point the timeline reaches once the client is done mutating the texture + pub acquire_point: u64, + ///the point the timeline reaches once the server is done with the dmatex and the client can access it again + pub release_point: u64, + } /// #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] pub struct TextBounds { @@ -1346,7 +1267,9 @@ pub mod drawable { /// #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] pub struct TextStyle { + ///Height of a character in meters pub character_height: f32, + ///Premultiplied text color pub color: stardust_xr_wire::values::Color, pub font: Option, pub text_align_x: XAlign, @@ -1412,18 +1335,12 @@ pub mod drawable { pub trait LinesAspect: crate::node::NodeType + super::SpatialAspect + super::OwnedAspect + super::SpatialRefAspect + std::fmt::Debug { ///Replace all polylines with the given lines fn set_lines(&self, lines: &[Line]) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (lines .iter() .map(|a| Ok(a)) .collect::>>()?); self.node() - .send_signal( - 16705186951373789081u64, - 17689001183742889136u64, - &data, - _fds, - )?; + .send_signal(16705186951373789081u64, 17689001183742889136u64, &data)?; let (lines) = data; tracing::trace!( ? lines, "Sent signal to server, {}::{}", "Lines", "set_lines" @@ -1495,14 +1412,12 @@ pub mod drawable { part_path: &str, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (id, part_path); self.node() .send_signal( 11775342128130118047u64, 18406803564448475833u64, &data, - _fds, )?; let (id, part_path) = data; tracing::trace!( @@ -1572,15 +1487,9 @@ pub mod drawable { pub trait ModelPartAspect: crate::node::NodeType + super::SpatialAspect + super::OwnedAspect + super::SpatialRefAspect + std::fmt::Debug { ///Set this model part's material to one that cuts a hole in the world. Often used for overlays/passthrough where you want to show the background through an object. fn apply_holdout_material(&self) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (); self.node() - .send_signal( - 7912164431074553740u64, - 13817793452575402942u64, - &data, - _fds, - )?; + .send_signal(7912164431074553740u64, 13817793452575402942u64, &data)?; let () = data; tracing::trace!( "Sent signal to server, {}::{}", "ModelPart", "apply_holdout_material" @@ -1593,15 +1502,9 @@ pub mod drawable { parameter_name: &str, value: MaterialParameter, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (parameter_name, value); self.node() - .send_signal( - 7912164431074553740u64, - 12609900228877593594u64, - &data, - _fds, - )?; + .send_signal(7912164431074553740u64, 12609900228877593594u64, &data)?; let (parameter_name, value) = data; tracing::trace!( ? parameter_name, ? value, "Sent signal to server, {}::{}", "ModelPart", @@ -1669,15 +1572,9 @@ pub mod drawable { pub trait TextAspect: crate::node::NodeType + super::SpatialAspect + super::OwnedAspect + super::SpatialRefAspect + std::fmt::Debug { ///Set the character height in meters fn set_character_height(&self, height: f32) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (height); self.node() - .send_signal( - 3129045917168168339u64, - 1124886941794143568u64, - &data, - _fds, - )?; + .send_signal(3129045917168168339u64, 1124886941794143568u64, &data)?; let (height) = data; tracing::trace!( ? height, "Sent signal to server, {}::{}", "Text", "set_character_height" @@ -1686,31 +1583,197 @@ pub mod drawable { } ///Set the text content fn set_text(&self, text: &str) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (text); self.node() - .send_signal( - 3129045917168168339u64, - 395974856293277940u64, - &data, - _fds, - )?; + .send_signal(3129045917168168339u64, 395974856293277940u64, &data)?; let (text) = data; tracing::trace!(? text, "Sent signal to server, {}::{}", "Text", "set_text"); Ok(()) } } + ///Import a Dmatex, the imported Dmatex has to be manually unregistered, the returned id is Client Local + pub fn import_dmatex( + _client: &std::sync::Arc, + dmatex_id: u64, + size: DmatexSize, + format: u32, + drm_format_modifier: u64, + srgb: bool, + array_layers: Option, + planes: &[DmatexPlane], + timeline_syncobj_fd: stardust_xr_wire::fd::ProtocolFd, + ) -> crate::node::NodeResult<()> { + let data = ( + dmatex_id, + size, + format, + drm_format_modifier, + srgb, + array_layers.map(|o| Ok::<_, crate::node::NodeError>(o)).transpose()?, + planes.iter().map(|a| Ok(a)).collect::>>()?, + timeline_syncobj_fd, + ); + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; + _client + .message_sender_handle + .signal(4u64, 0u64, 5202664904415071827u64, &serialized_data, fds)?; + let ( + dmatex_id, + size, + format, + drm_format_modifier, + srgb, + array_layers, + planes, + timeline_syncobj_fd, + ) = data; + tracing::trace!( + ? dmatex_id, ? size, ? format, ? drm_format_modifier, ? srgb, ? array_layers, + ? planes, ? timeline_syncobj_fd, "Sent signal to server, {}::{}", + "Interface", "import_dmatex" + ); + Ok(()) + } + ///Exports a Dmatex Uid for sharing between clients + pub async fn export_dmatex_uid( + _client: &std::sync::Arc, + dmatex_id: u64, + ) -> crate::node::NodeResult { + let data = (dmatex_id); + { + let (dmatex_id) = &data; + tracing::trace!( + ? dmatex_id, "Called method on server, {}::{}", "Interface", + "export_dmatex_uid" + ); + } + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; + let (message, message_fds) = _client + .message_sender_handle + .method(4u64, 0u64, 2247267269053194767u64, &serialized_data, fds) + .await? + .map_err(|e| crate::node::NodeError::ReturnedError { + e, + })? + .into_components(); + let result: u64 = stardust_xr_wire::flex::deserialize(&message, message_fds)?; + let deserialized = result; + tracing::trace!( + "return" = ? deserialized, "Method return from server, {}::{}", "Interface", + "export_dmatex_uid" + ); + Ok(deserialized) + } + ///Imports a shared Dmatex Uid, holding this id will keep the underlying dmatex alive + pub fn import_dmatex_uid( + _client: &std::sync::Arc, + dmatex_id: u64, + dmatex_uid: u64, + ) -> crate::node::NodeResult<()> { + let data = (dmatex_id, dmatex_uid); + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; + _client + .message_sender_handle + .signal(4u64, 0u64, 5604115908701744320u64, &serialized_data, fds)?; + let (dmatex_id, dmatex_uid) = data; + tracing::trace!( + ? dmatex_id, ? dmatex_uid, "Sent signal to server, {}::{}", "Interface", + "import_dmatex_uid" + ); + Ok(()) + } + ///Mark a Dmatex as unused, once all ids referencing the same Dmatex are unregisterd the server may destroy its internal representation of the Dmatex, this invalidates the used handle + pub fn unregister_dmatex( + _client: &std::sync::Arc, + dmatex_id: u64, + ) -> crate::node::NodeResult<()> { + let data = (dmatex_id); + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; + _client + .message_sender_handle + .signal(4u64, 0u64, 15846108642868241016u64, &serialized_data, fds)?; + let (dmatex_id) = data; + tracing::trace!( + ? dmatex_id, "Sent signal to server, {}::{}", "Interface", + "unregister_dmatex" + ); + Ok(()) + } + ///get the id of the primary device used for rendering, will return a DrmRenderNode id + pub async fn get_primary_render_device_id( + _client: &std::sync::Arc, + ) -> crate::node::NodeResult { + let data = (); + { + let () = &data; + tracing::trace!( + "Called method on server, {}::{}", "Interface", + "get_primary_render_device_id" + ); + } + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; + let (message, message_fds) = _client + .message_sender_handle + .method(4u64, 0u64, 16013200258148922551u64, &serialized_data, fds) + .await? + .map_err(|e| crate::node::NodeError::ReturnedError { + e, + })? + .into_components(); + let result: u64 = stardust_xr_wire::flex::deserialize(&message, message_fds)?; + let deserialized = result; + tracing::trace!( + "return" = ? deserialized, "Method return from server, {}::{}", "Interface", + "get_primary_render_device_id" + ); + Ok(deserialized) + } + ///enumerates all the Dmatex formats supported by the server + pub async fn enumerate_dmatex_formats( + _client: &std::sync::Arc, + render_node_id: u64, + ) -> crate::node::NodeResult> { + let data = (render_node_id); + { + let (render_node_id) = &data; + tracing::trace!( + ? render_node_id, "Called method on server, {}::{}", "Interface", + "enumerate_dmatex_formats" + ); + } + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; + let (message, message_fds) = _client + .message_sender_handle + .method(4u64, 0u64, 14109465327684673699u64, &serialized_data, fds) + .await? + .map_err(|e| crate::node::NodeError::ReturnedError { + e, + })? + .into_components(); + let result: Vec = stardust_xr_wire::flex::deserialize( + &message, + message_fds, + )?; + let deserialized = result + .into_iter() + .map(|a| Ok(a)) + .collect::, crate::node::NodeError>>()?; + tracing::trace!( + "return" = ? deserialized, "Method return from server, {}::{}", "Interface", + "enumerate_dmatex_formats" + ); + Ok(deserialized) + } ///Set the sky texture to a given HDRI file. pub fn set_sky_tex( _client: &std::sync::Arc, tex: Option<&stardust_xr_wire::values::ResourceID>, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (tex.map(|o| Ok::<_, crate::node::NodeError>(o)).transpose()?); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(4u64, 0u64, 4424860741442403592u64, &serialized_data, _fds)?; + .signal(4u64, 0u64, 4424860741442403592u64, &serialized_data, fds)?; let (tex) = data; tracing::trace!( ? tex, "Sent signal to server, {}::{}", "Interface", "set_sky_tex" @@ -1722,12 +1785,11 @@ pub mod drawable { _client: &std::sync::Arc, light: Option<&stardust_xr_wire::values::ResourceID>, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (light.map(|o| Ok::<_, crate::node::NodeError>(o)).transpose()?); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(4u64, 0u64, 6210987039553590011u64, &serialized_data, _fds)?; + .signal(4u64, 0u64, 6210987039553590011u64, &serialized_data, fds)?; let (light) = data; tracing::trace!( ? light, "Sent signal to server, {}::{}", "Interface", "set_sky_light" @@ -1743,17 +1805,16 @@ pub mod drawable { lines: &[Line], ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = ( id, parent.node().id, transform, lines.iter().map(|a| Ok(a)).collect::>>()?, ); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(4u64, 0u64, 17691651736865216822u64, &serialized_data, _fds)?; + .signal(4u64, 0u64, 17691651736865216822u64, &serialized_data, fds)?; let (id, parent, transform, lines) = data; tracing::trace!( ? id, ? parent, ? transform, ? lines, "Sent signal to server, {}::{}", @@ -1771,12 +1832,11 @@ pub mod drawable { model: &stardust_xr_wire::values::ResourceID, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (id, parent.node().id, transform, model); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(4u64, 0u64, 8647852218278439936u64, &serialized_data, _fds)?; + .signal(4u64, 0u64, 8647852218278439936u64, &serialized_data, fds)?; let (id, parent, transform, model) = data; tracing::trace!( ? id, ? parent, ? transform, ? model, "Sent signal to server, {}::{}", @@ -1795,12 +1855,11 @@ pub mod drawable { style: TextStyle, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (id, parent.node().id, transform, text, style); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(4u64, 0u64, 11386227176670607870u64, &serialized_data, _fds)?; + .signal(4u64, 0u64, 11386227176670607870u64, &serialized_data, fds)?; let (id, parent, transform, text, style) = data; tracing::trace!( ? id, ? parent, ? transform, ? text, ? style, @@ -1828,14 +1887,19 @@ pub mod input { ///A hand joint. Distance from input handler's field is given because it's cheap to calculate and laggy to request from the server. #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] pub struct Joint { + ///Position of the joint relative to the input handler's field. pub position: stardust_xr_wire::values::Vector3, + ///Orientation of the joint relative to the input handler's field. pub rotation: stardust_xr_wire::values::Quaternion, + ///Radius of the joint in meters. pub radius: f32, + ///Distance from the center of the joint to the input handler's field pub distance: f32, } /// #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] pub struct Finger { + ///Joint inside the fingertip offset by the radius. pub tip: Joint, pub distal: Joint, pub intermediate: Joint, @@ -1868,6 +1932,10 @@ pub mod input { pub struct Pointer { pub origin: stardust_xr_wire::values::Vector3, pub orientation: stardust_xr_wire::values::Quaternion, + /** + The point that is the most inside the input handler's field. + Useful for telling how close to the center it's pointing or for thin objects can take the place of a point of intersection. + */ pub deepest_point: stardust_xr_wire::values::Vector3, } ///Represents a controller, pen tip, spatial cursor, etc. that is just a single point. @@ -1879,11 +1947,17 @@ pub mod input { ///Information about a given input method's state. All coordinates are relative to the InputHandler. #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] pub struct InputData { + ///Used to uniquely identify the input method so state can be tracked across input events. pub id: u64, + ///All vectors and quaternions are relative to the input handler if deserialized. pub input: InputDataType, + ///Closest distance from the input handler to the field. pub distance: f32, + ///Non-spatial data in a map. pub datamap: stardust_xr_wire::values::Datamap, + ///There are [order] objects that got this input data before this one. pub order: u32, + ///Is this input handler capturing this input method? pub captured: bool, } ///Node representing a spatial input device @@ -1943,15 +2017,9 @@ pub mod input { &self, handler: &impl InputHandlerAspect, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (handler.node().id); self.node() - .send_signal( - 2611007814387963428u64, - 12158986667525139020u64, - &data, - _fds, - )?; + .send_signal(2611007814387963428u64, 12158986667525139020u64, &data)?; let (handler) = data; tracing::trace!( ? handler, "Sent signal to server, {}::{}", "InputMethodRef", @@ -1964,15 +2032,9 @@ pub mod input { &self, handler: &impl InputHandlerAspect, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (handler.node().id); self.node() - .send_signal( - 2611007814387963428u64, - 11905596878821798323u64, - &data, - _fds, - )?; + .send_signal(2611007814387963428u64, 11905596878821798323u64, &data)?; let (handler) = data; tracing::trace!( ? handler, "Sent signal to server, {}::{}", "InputMethodRef", "release" @@ -2088,6 +2150,7 @@ pub mod input { 6944316585732678571u64 => { let (handler, field): (u64, u64) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? handler, ? field, "Got signal from server, {}::{}", @@ -2099,7 +2162,7 @@ pub mod input { }) } 11807638350036597049u64 => { - let (id): (u64) = stardust_xr_wire::flex::deserialize(_data)?; + let (id): (u64) = stardust_xr_wire::flex::deserialize(_data, _fds)?; tracing::trace!( ? id, "Got signal from server, {}::{}", "InputMethod", "request_capture_handler" @@ -2109,7 +2172,7 @@ pub mod input { }) } 9300665394087171854u64 => { - let (id): (u64) = stardust_xr_wire::flex::deserialize(_data)?; + let (id): (u64) = stardust_xr_wire::flex::deserialize(_data, _fds)?; tracing::trace!( ? id, "Got signal from server, {}::{}", "InputMethod", "release_handler" @@ -2119,7 +2182,7 @@ pub mod input { }) } 7635230773176050803u64 => { - let (id): (u64) = stardust_xr_wire::flex::deserialize(_data)?; + let (id): (u64) = stardust_xr_wire::flex::deserialize(_data, _fds)?; tracing::trace!( ? id, "Got signal from server, {}::{}", "InputMethod", "destroy_handler" @@ -2177,15 +2240,9 @@ pub mod input { input: InputDataType, datamap: &stardust_xr_wire::values::Datamap, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (input, datamap); self.node() - .send_signal( - 14883688361483968991u64, - 9469903295692537735u64, - &data, - _fds, - )?; + .send_signal(14883688361483968991u64, 9469903295692537735u64, &data)?; let (input, datamap) = data; tracing::trace!( ? input, ? datamap, "Sent signal to server, {}::{}", "InputMethod", @@ -2198,18 +2255,12 @@ pub mod input { &self, handlers: &[InputHandler], ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (handlers .iter() .map(|a| Ok(a.node().id)) .collect::>>()?); self.node() - .send_signal( - 14883688361483968991u64, - 4447101880184876824u64, - &data, - _fds, - )?; + .send_signal(14883688361483968991u64, 4447101880184876824u64, &data)?; let (handlers) = data; tracing::trace!( ? handlers, "Sent signal to server, {}::{}", "InputMethod", @@ -2222,18 +2273,12 @@ pub mod input { &self, handlers: &[InputHandler], ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (handlers .iter() .map(|a| Ok(a.node().id)) .collect::>>()?); self.node() - .send_signal( - 14883688361483968991u64, - 4141712352465076448u64, - &data, - _fds, - )?; + .send_signal(14883688361483968991u64, 4141712352465076448u64, &data)?; let (handlers) = data; tracing::trace!( ? handlers, "Sent signal to server, {}::{}", "InputMethod", @@ -2326,6 +2371,7 @@ pub mod input { 1784186157485816199u64 => { let (method, data): (u64, InputData) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? method, ? data, "Got signal from server, {}::{}", @@ -2339,6 +2385,7 @@ pub mod input { 12767704399235128028u64 => { let (data): (InputData) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? data, "Got signal from server, {}::{}", "InputHandler", @@ -2349,7 +2396,10 @@ pub mod input { }) } 6474489366123796070u64 => { - let (method): (u64) = stardust_xr_wire::flex::deserialize(_data)?; + let (method): (u64) = stardust_xr_wire::flex::deserialize( + _data, + _fds, + )?; tracing::trace!( ? method, "Got signal from server, {}::{}", "InputHandler", "input_left" @@ -2395,12 +2445,11 @@ pub mod input { datamap: &stardust_xr_wire::values::Datamap, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (id, parent.node().id, transform, initial_data, datamap); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(3u64, 0u64, 11977582531774730283u64, &serialized_data, _fds)?; + .signal(3u64, 0u64, 11977582531774730283u64, &serialized_data, fds)?; let (id, parent, transform, initial_data, datamap) = data; tracing::trace!( ? id, ? parent, ? transform, ? initial_data, ? datamap, @@ -2418,12 +2467,11 @@ pub mod input { field: &impl FieldAspect, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (id, parent.node().id, transform, field.node().id); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(3u64, 0u64, 1654491336591158898u64, &serialized_data, _fds)?; + .signal(3u64, 0u64, 1654491336591158898u64, &serialized_data, fds)?; let (id, parent, transform, field) = data; tracing::trace!( ? id, ? parent, ? transform, ? field, "Sent signal to server, {}::{}", @@ -2499,15 +2547,9 @@ pub mod item { pub trait ItemAspect: crate::node::NodeType + super::SpatialAspect + super::OwnedAspect + super::SpatialRefAspect + std::fmt::Debug { /// fn release(&self) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (); self.node() - .send_signal( - 18318655529277677339u64, - 11905596878821798323u64, - &data, - _fds, - )?; + .send_signal(18318655529277677339u64, 11905596878821798323u64, &data)?; let () = data; tracing::trace!("Sent signal to server, {}::{}", "Item", "release"); Ok(()) @@ -2593,7 +2635,10 @@ pub mod item { ) -> Result { match signal_id { 14821884892980204849u64 => { - let (item_id): (u64) = stardust_xr_wire::flex::deserialize(_data)?; + let (item_id): (u64) = stardust_xr_wire::flex::deserialize( + _data, + _fds, + )?; tracing::trace!( ? item_id, "Got signal from server, {}::{}", "ItemAcceptor", "release_item" @@ -2700,6 +2745,7 @@ pub mod item { 1751367302976798762u64 => { let (item_id, acceptor_id): (u64, u64) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? item_id, ? acceptor_id, "Got signal from server, {}::{}", @@ -2713,6 +2759,7 @@ pub mod item { 14821884892980204849u64 => { let (item_id, acceptor_id): (u64, u64) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? item_id, ? acceptor_id, "Got signal from server, {}::{}", @@ -2724,14 +2771,14 @@ pub mod item { }) } 11215449886948753686u64 => { - let (id): (u64) = stardust_xr_wire::flex::deserialize(_data)?; + let (id): (u64) = stardust_xr_wire::flex::deserialize(_data, _fds)?; tracing::trace!( ? id, "Got signal from server, {}::{}", "ItemUi", "destroy_item" ); Ok(ItemUiEvent::DestroyItem { id: id }) } 3521554848760623636u64 => { - let (id): (u64) = stardust_xr_wire::flex::deserialize(_data)?; + let (id): (u64) = stardust_xr_wire::flex::deserialize(_data, _fds)?; tracing::trace!( ? id, "Got signal from server, {}::{}", "ItemUi", "destroy_acceptor" @@ -2906,7 +2953,10 @@ pub mod item_camera { ) -> Result { match signal_id { 15524466827491111758u64 => { - let (item): (u64) = stardust_xr_wire::flex::deserialize(_data)?; + let (item): (u64) = stardust_xr_wire::flex::deserialize( + _data, + _fds, + )?; tracing::trace!( ? item, "Got signal from server, {}::{}", "CameraItemUi", "create_item" @@ -2918,6 +2968,7 @@ pub mod item_camera { 16628549773568263004u64 => { let (acceptor, acceptor_field): (u64, u64) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? acceptor, ? acceptor_field, "Got signal from server, {}::{}", @@ -3055,7 +3106,10 @@ pub mod item_camera { ) -> Result { match signal_id { 1751367302976798762u64 => { - let (item): (u64) = stardust_xr_wire::flex::deserialize(_data)?; + let (item): (u64) = stardust_xr_wire::flex::deserialize( + _data, + _fds, + )?; tracing::trace!( ? item, "Got signal from server, {}::{}", "CameraItemAcceptor", "capture_item" @@ -3095,15 +3149,9 @@ pub mod item_camera { &self, item: &impl CameraItemAspect, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (item.node().id); self.node() - .send_signal( - 5036088114779304421u64, - 1751367302976798762u64, - &data, - _fds, - )?; + .send_signal(5036088114779304421u64, 1751367302976798762u64, &data)?; let (item) = data; tracing::trace!( ? item, "Sent signal to server, {}::{}", "CameraItemAcceptor", @@ -3122,7 +3170,6 @@ pub mod item_camera { px_size: impl Into>, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = ( id, parent.node().id, @@ -3130,10 +3177,10 @@ pub mod item_camera { proj_matrix.into(), px_size.into(), ); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(11u64, 0u64, 16398826726504952950u64, &serialized_data, _fds)?; + .signal(11u64, 0u64, 16398826726504952950u64, &serialized_data, fds)?; let (id, parent, transform, proj_matrix, px_size) = data; tracing::trace!( ? id, ? parent, ? transform, ? proj_matrix, ? px_size, @@ -3146,12 +3193,11 @@ pub mod item_camera { pub fn register_camera_item_ui( _client: &std::sync::Arc, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(11u64, 0u64, 13470969625663359032u64, &serialized_data, _fds)?; + .signal(11u64, 0u64, 13470969625663359032u64, &serialized_data, fds)?; let () = data; tracing::trace!( "Sent signal to server, {}::{}", "Interface", "register_camera_item_ui" @@ -3167,12 +3213,11 @@ pub mod item_camera { field: &impl FieldAspect, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (id, parent.node().id, transform, field.node().id); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(11u64, 0u64, 13070169044031356364u64, &serialized_data, _fds)?; + .signal(11u64, 0u64, 13070169044031356364u64, &serialized_data, fds)?; let (id, parent, transform, field) = data; tracing::trace!( ? id, ? parent, ? transform, ? field, "Sent signal to server, {}::{}", @@ -3205,12 +3250,19 @@ pub mod item_panel { ///The state of the panel item's toplevel. #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] pub struct ToplevelInfo { + ///The UID of the panel item of the parent of this toplevel, if it exists pub parent: Option, + ///Equivalent to the window title pub title: Option, + ///Application identifier, see pub app_id: Option, + ///Current size in pixels pub size: stardust_xr_wire::values::Vector2, + ///Recommended minimum size in pixels pub min_size: Option>, + ///Recommended maximum size in pixels pub max_size: Option>, + ///Surface geometry pub logical_rectangle: Geometry, } ///Data on positioning a child. @@ -3219,7 +3271,9 @@ pub mod item_panel { pub id: u64, pub parent: SurfaceId, pub geometry: Geometry, + ///Relative to parent. 0 is same level, -1 is below, 1 is above, etc. pub z_order: i32, + ///Whether this child receives input or is purely visual. pub receives_input: bool, } ///The init data for the panel item. @@ -3228,7 +3282,9 @@ pub mod item_panel { pub cursor: Option, pub toplevel: ToplevelInfo, pub children: Vec, + ///The surface, if any, that has exclusive input to the pointer. pub pointer_grab: Option, + ///The surface, if any, that has exclusive input to the keyboard. pub keyboard_grab: Option, } ///An item that represents a toplevel 2D window's surface (base window) and all its children (context menus, modals, etc.). @@ -3326,7 +3382,10 @@ pub mod item_panel { ) -> Result { match signal_id { 1408884359956576105u64 => { - let (parent_id): (u64) = stardust_xr_wire::flex::deserialize(_data)?; + let (parent_id): (u64) = stardust_xr_wire::flex::deserialize( + _data, + _fds, + )?; tracing::trace!( ? parent_id, "Got signal from server, {}::{}", "PanelItem", "toplevel_parent_changed" @@ -3336,7 +3395,10 @@ pub mod item_panel { }) } 566483566315648641u64 => { - let (title): (String) = stardust_xr_wire::flex::deserialize(_data)?; + let (title): (String) = stardust_xr_wire::flex::deserialize( + _data, + _fds, + )?; tracing::trace!( ? title, "Got signal from server, {}::{}", "PanelItem", "toplevel_title_changed" @@ -3346,7 +3408,10 @@ pub mod item_panel { }) } 8706869778156655494u64 => { - let (app_id): (String) = stardust_xr_wire::flex::deserialize(_data)?; + let (app_id): (String) = stardust_xr_wire::flex::deserialize( + _data, + _fds, + )?; tracing::trace!( ? app_id, "Got signal from server, {}::{}", "PanelItem", "toplevel_app_id_changed" @@ -3356,7 +3421,10 @@ pub mod item_panel { }) } 11059551561818960198u64 => { - let (active): (bool) = stardust_xr_wire::flex::deserialize(_data)?; + let (active): (bool) = stardust_xr_wire::flex::deserialize( + _data, + _fds, + )?; tracing::trace!( ? active, "Got signal from server, {}::{}", "PanelItem", "toplevel_fullscreen_active" @@ -3366,7 +3434,7 @@ pub mod item_panel { }) } 3715781852227007625u64 => { - let (): () = stardust_xr_wire::flex::deserialize(_data)?; + let (): () = stardust_xr_wire::flex::deserialize(_data, _fds)?; tracing::trace!( "Got signal from server, {}::{}", "PanelItem", "toplevel_move_request" @@ -3377,6 +3445,7 @@ pub mod item_panel { 4540754955116125050u64 => { let (up, down, left, right): (bool, bool, bool, bool) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? up, ? down, ? left, ? right, "Got signal from server, {}::{}", @@ -3392,6 +3461,7 @@ pub mod item_panel { 3665525014775618530u64 => { let (size): (stardust_xr_wire::values::Vector2) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? size, "Got signal from server, {}::{}", "PanelItem", @@ -3404,6 +3474,7 @@ pub mod item_panel { 6092877811616586203u64 => { let (geometry): (Geometry) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? geometry, "Got signal from server, {}::{}", "PanelItem", @@ -3414,7 +3485,7 @@ pub mod item_panel { }) } 12365625385177885025u64 => { - let (): () = stardust_xr_wire::flex::deserialize(_data)?; + let (): () = stardust_xr_wire::flex::deserialize(_data, _fds)?; tracing::trace!( "Got signal from server, {}::{}", "PanelItem", "hide_cursor" ); @@ -3423,6 +3494,7 @@ pub mod item_panel { 13878060402106144481u64 => { let (uid, info): (u64, ChildInfo) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? uid, ? info, "Got signal from server, {}::{}", "PanelItem", @@ -3436,6 +3508,7 @@ pub mod item_panel { 4614990113965355127u64 => { let (uid, geometry): (u64, Geometry) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? uid, ? geometry, "Got signal from server, {}::{}", "PanelItem", @@ -3447,7 +3520,7 @@ pub mod item_panel { }) } 7048616010698587017u64 => { - let (uid): (u64) = stardust_xr_wire::flex::deserialize(_data)?; + let (uid): (u64) = stardust_xr_wire::flex::deserialize(_data, _fds)?; tracing::trace!( ? uid, "Got signal from server, {}::{}", "PanelItem", "destroy_child" @@ -3487,15 +3560,9 @@ pub mod item_panel { &self, model_part: &impl ModelPartAspect, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (model_part.node().id); self.node() - .send_signal( - 16007573185838633179u64, - 12984352657777750687u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 12984352657777750687u64, &data)?; let (model_part) = data; tracing::trace!( ? model_part, "Sent signal to server, {}::{}", "PanelItem", @@ -3509,15 +3576,9 @@ pub mod item_panel { surface: SurfaceId, model_part: &impl ModelPartAspect, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (surface, model_part.node().id); self.node() - .send_signal( - 16007573185838633179u64, - 5538717944649978650u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 5538717944649978650u64, &data)?; let (surface, model_part) = data; tracing::trace!( ? surface, ? model_part, "Sent signal to server, {}::{}", "PanelItem", @@ -3529,15 +3590,9 @@ pub mod item_panel { The panel item UI handler or panel item acceptor will drop the panel item if this succeeds.*/ fn close_toplevel(&self) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (); self.node() - .send_signal( - 16007573185838633179u64, - 11149391162473273576u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 11149391162473273576u64, &data)?; let () = data; tracing::trace!( "Sent signal to server, {}::{}", "PanelItem", "close_toplevel" @@ -3546,15 +3601,9 @@ pub mod item_panel { } ///Request a resize of the surface to whatever size the 2D app wants. fn auto_size_toplevel(&self) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (); self.node() - .send_signal( - 16007573185838633179u64, - 7177229187692151305u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 7177229187692151305u64, &data)?; let () = data; tracing::trace!( "Sent signal to server, {}::{}", "PanelItem", "auto_size_toplevel" @@ -3566,15 +3615,9 @@ pub mod item_panel { &self, size: impl Into>, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (size.into()); self.node() - .send_signal( - 16007573185838633179u64, - 8102855835344875634u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 8102855835344875634u64, &data)?; let (size) = data; tracing::trace!( ? size, "Sent signal to server, {}::{}", "PanelItem", "set_toplevel_size" @@ -3586,15 +3629,9 @@ pub mod item_panel { &self, focused: bool, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (focused); self.node() - .send_signal( - 16007573185838633179u64, - 3934600665134956080u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 3934600665134956080u64, &data)?; let (focused) = data; tracing::trace!( ? focused, "Sent signal to server, {}::{}", "PanelItem", @@ -3608,15 +3645,9 @@ pub mod item_panel { surface: SurfaceId, position: impl Into>, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (surface, position.into()); self.node() - .send_signal( - 16007573185838633179u64, - 16749501366142443858u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 16749501366142443858u64, &data)?; let (surface, position) = data; tracing::trace!( ? surface, ? position, "Sent signal to server, {}::{}", "PanelItem", @@ -3630,15 +3661,9 @@ pub mod item_panel { surface: SurfaceId, delta: impl Into>, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (surface, delta.into()); self.node() - .send_signal( - 16007573185838633179u64, - 8178111286759258039u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 8178111286759258039u64, &data)?; let (surface, delta) = data; tracing::trace!( ? surface, ? delta, "Sent signal to server, {}::{}", "PanelItem", @@ -3653,15 +3678,9 @@ pub mod item_panel { button: u32, pressed: bool, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (surface, button, pressed); self.node() - .send_signal( - 16007573185838633179u64, - 1617963334017359776u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 1617963334017359776u64, &data)?; let (surface, button, pressed) = data; tracing::trace!( ? surface, ? button, ? pressed, "Sent signal to server, {}::{}", @@ -3678,15 +3697,9 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m scroll_distance: impl Into>, scroll_steps: impl Into>, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (surface, scroll_distance.into(), scroll_steps.into()); self.node() - .send_signal( - 16007573185838633179u64, - 18077910517219850499u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 18077910517219850499u64, &data)?; let (surface, scroll_distance, scroll_steps) = data; tracing::trace!( ? surface, ? scroll_distance, ? scroll_steps, @@ -3699,15 +3712,9 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m &self, surface: SurfaceId, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (surface); self.node() - .send_signal( - 16007573185838633179u64, - 13177724628894942354u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 13177724628894942354u64, &data)?; let (surface) = data; tracing::trace!( ? surface, "Sent signal to server, {}::{}", "PanelItem", @@ -3723,15 +3730,9 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m key: u32, pressed: bool, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (surface, keymap_id, key, pressed); self.node() - .send_signal( - 16007573185838633179u64, - 18230480350930328965u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 18230480350930328965u64, &data)?; let (surface, keymap_id, key, pressed) = data; tracing::trace!( ? surface, ? keymap_id, ? key, ? pressed, @@ -3746,15 +3747,9 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m uid: u32, position: impl Into>, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (surface, uid, position.into()); self.node() - .send_signal( - 16007573185838633179u64, - 10543081656468919422u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 10543081656468919422u64, &data)?; let (surface, uid, position) = data; tracing::trace!( ? surface, ? uid, ? position, "Sent signal to server, {}::{}", @@ -3768,15 +3763,9 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m uid: u32, position: impl Into>, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (uid, position.into()); self.node() - .send_signal( - 16007573185838633179u64, - 15126475688563381777u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 15126475688563381777u64, &data)?; let (uid, position) = data; tracing::trace!( ? uid, ? position, "Sent signal to server, {}::{}", "PanelItem", @@ -3786,15 +3775,9 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m } ///Release a touch from its surface. fn touch_up(&self, uid: u32) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (uid); self.node() - .send_signal( - 16007573185838633179u64, - 6589027081119653997u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 6589027081119653997u64, &data)?; let (uid) = data; tracing::trace!( ? uid, "Sent signal to server, {}::{}", "PanelItem", "touch_up" @@ -3803,15 +3786,9 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m } ///Reset all input, such as pressed keys and pointer clicks and touches. Useful for when it's newly captured into an item acceptor to make sure no input gets stuck. fn reset_input(&self) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (); self.node() - .send_signal( - 16007573185838633179u64, - 14629122800709746500u64, - &data, - _fds, - )?; + .send_signal(16007573185838633179u64, 14629122800709746500u64, &data)?; let () = data; tracing::trace!("Sent signal to server, {}::{}", "PanelItem", "reset_input"); Ok(()) @@ -3907,6 +3884,7 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m 15524466827491111758u64 => { let (item, initial_data): (u64, PanelItemInitData) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? item, ? initial_data, "Got signal from server, {}::{}", @@ -3920,6 +3898,7 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m 16628549773568263004u64 => { let (acceptor, acceptor_field): (u64, u64) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? acceptor, ? acceptor_field, "Got signal from server, {}::{}", @@ -4059,6 +4038,7 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m 1751367302976798762u64 => { let (item, initial_data): (u64, PanelItemInitData) = stardust_xr_wire::flex::deserialize( _data, + _fds, )?; tracing::trace!( ? item, ? initial_data, "Got signal from server, {}::{}", @@ -4100,15 +4080,9 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m &self, item: &impl PanelItemAspect, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (item.node().id); self.node() - .send_signal( - 6398932320740499836u64, - 1751367302976798762u64, - &data, - _fds, - )?; + .send_signal(6398932320740499836u64, 1751367302976798762u64, &data)?; let (item) = data; tracing::trace!( ? item, "Sent signal to server, {}::{}", "PanelItemAcceptor", @@ -4122,7 +4096,6 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m _client: &std::sync::Arc, keymap: &str, ) -> crate::node::NodeResult { - let mut _fds = Vec::new(); let data = (keymap); { let (keymap) = &data; @@ -4131,16 +4104,16 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m "register_keymap" ); } - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; - let message = _client + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; + let (message, message_fds) = _client .message_sender_handle - .method(12u64, 0u64, 13267771052011565359u64, &serialized_data, _fds) + .method(12u64, 0u64, 13267771052011565359u64, &serialized_data, fds) .await? .map_err(|e| crate::node::NodeError::ReturnedError { e, })? - .into_message(); - let result: u64 = stardust_xr_wire::flex::deserialize(&message)?; + .into_components(); + let result: u64 = stardust_xr_wire::flex::deserialize(&message, message_fds)?; let deserialized = result; tracing::trace!( "return" = ? deserialized, "Method return from server, {}::{}", "Interface", @@ -4153,7 +4126,6 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m _client: &std::sync::Arc, keymap_id: u64, ) -> crate::node::NodeResult { - let mut _fds = Vec::new(); let data = (keymap_id); { let (keymap_id) = &data; @@ -4161,16 +4133,16 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m ? keymap_id, "Called method on server, {}::{}", "Interface", "get_keymap" ); } - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; - let message = _client + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; + let (message, message_fds) = _client .message_sender_handle - .method(12u64, 0u64, 18393315648981916968u64, &serialized_data, _fds) + .method(12u64, 0u64, 18393315648981916968u64, &serialized_data, fds) .await? .map_err(|e| crate::node::NodeError::ReturnedError { e, })? - .into_message(); - let result: String = stardust_xr_wire::flex::deserialize(&message)?; + .into_components(); + let result: String = stardust_xr_wire::flex::deserialize(&message, message_fds)?; let deserialized = result; tracing::trace!( "return" = ? deserialized, "Method return from server, {}::{}", "Interface", @@ -4182,12 +4154,11 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m pub fn register_panel_item_ui( _client: &std::sync::Arc, ) -> crate::node::NodeResult<()> { - let mut _fds = Vec::new(); let data = (); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(12u64, 0u64, 13016197282381545765u64, &serialized_data, _fds)?; + .signal(12u64, 0u64, 13016197282381545765u64, &serialized_data, fds)?; let () = data; tracing::trace!( "Sent signal to server, {}::{}", "Interface", "register_panel_item_ui" @@ -4203,12 +4174,11 @@ Scroll steps is a value in columns/rows corresponding to the wheel clicks of a m field: &impl FieldAspect, ) -> crate::node::NodeResult { { - let mut _fds = Vec::new(); let data = (id, parent.node().id, transform, field.node().id); - let serialized_data = stardust_xr_wire::flex::serialize(&data)?; + let (serialized_data, fds) = stardust_xr_wire::flex::serialize(&data)?; _client .message_sender_handle - .signal(12u64, 0u64, 793626320493717815u64, &serialized_data, _fds)?; + .signal(12u64, 0u64, 793626320493717815u64, &serialized_data, fds)?; let (id, parent, transform, field) = data; tracing::trace!( ? id, ? parent, ? transform, ? field, "Sent signal to server, {}::{}", diff --git a/gluon/Cargo.toml b/gluon/Cargo.toml index 80c9eb0..9de6748 100644 --- a/gluon/Cargo.toml +++ b/gluon/Cargo.toml @@ -1,9 +1,9 @@ [package] edition = "2024" name = "stardust-xr-gluon" -version = "2.0.0" authors = ["Nova King bool { self.abort_handle.is_finished() } } +impl From> for AbortOnDrop { + fn from(value: JoinHandle) -> Self { + Self { + abort_handle: value.abort_handle(), + } + } +} + +impl From for AbortOnDrop { + fn from(abort_handle: AbortHandle) -> Self { + Self { abort_handle } + } +} impl Drop for AbortOnDrop { fn drop(&mut self) { self.abort_handle.abort(); @@ -458,7 +470,7 @@ mod tests { assert!(!abort_handle2.is_finished(), "Task should be running"); let _ = trigger_tx2.send(()); tokio::time::sleep(Duration::from_millis(50)).await; - abort_handle2.abort(); + drop(abort_handle2); tokio::time::sleep(Duration::from_millis(50)).await; } diff --git a/protocol/Cargo.toml b/protocol/Cargo.toml index 17cf5bf..47e1dd8 100644 --- a/protocol/Cargo.toml +++ b/protocol/Cargo.toml @@ -1,9 +1,9 @@ [package] edition = "2024" name = "stardust-xr-protocol" -version = "2.0.0" authors = ["Nova King "] description = "Base wire/serialization format for the Stardust XR display server" +version.workspace = true license.workspace = true repository.workspace = true homepage.workspace = true @@ -34,7 +34,6 @@ serde = { version = "1.0.196", features = ["derive"] } serde_repr = "0.1.18" # values -color-eyre = "0.6.2" shiva-color-rs = "0.0.1" mint = { version = "0.5.9", features = ["serde"] } diff --git a/wire/src/fd.rs b/wire/src/fd.rs new file mode 100644 index 0000000..e10c4da --- /dev/null +++ b/wire/src/fd.rs @@ -0,0 +1,116 @@ +use std::{ + cell::RefCell, + error::Error, + os::fd::{AsFd, AsRawFd, IntoRawFd, OwnedFd, RawFd}, +}; + +use serde::{Deserialize, Serialize}; +use tracing::warn; + +#[derive(Debug)] +pub struct ProtocolFd(pub OwnedFd); + +pub fn with_fd_serialization_ctx( + func: impl FnOnce() -> Result, +) -> Result<(T, Vec), E> { + FD_SERIALIZATION_CTX.set(Some(Vec::new())); + let v = func(); + let Some(fds) = FD_SERIALIZATION_CTX.with_borrow_mut(|v| v.take()) else { + unreachable!() + }; + Ok((v?, fds)) +} + +pub fn with_fd_deserialization_ctx( + fds: impl IntoIterator, + func: impl FnOnce() -> T, +) -> T { + let fds = fds.into_iter().map(Some).collect::>(); + FD_DESERIALIZATION_CTX.set(Some(fds)); + let v = func(); + let Some(fds) = FD_DESERIALIZATION_CTX.with_borrow_mut(|v| v.take()) else { + unreachable!() + }; + let count = fds.into_iter().filter_map(|v| v).count(); + if count != 0 { + warn!("{count} unused fds during deserialization"); + } + v +} + +impl Serialize for ProtocolFd { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let index = FD_SERIALIZATION_CTX.with_borrow_mut(|ctx| { + let Some(ctx) = ctx else { + return Err(::custom( + "tried to serialize ProtocolFd without fd serialization context", + )); + }; + ctx.push(self.0.try_clone().unwrap()); + Ok(ctx.len() - 1) + })?; + serializer.serialize_u32(index as u32) + } +} +impl<'de> Deserialize<'de> for ProtocolFd { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let fd = FD_DESERIALIZATION_CTX.with_borrow_mut(|ctx| { + let Some(ctx) = ctx else { + return Err(::custom( + "tried to deserialize ProtocolFd without fd deserialization context", + )); + }; + let index = ::deserialize(deserializer)?; + let Some(fd_option) = ctx.get_mut(index as usize) else { + return Err(::custom( + "tried to deserialize fd not present in the deserialization context", + )); + }; + let Some(fd) = fd_option.take() else { + return Err(::custom( + "tried to deserialize the same fd twice, should be impossible", + )); + }; + + Ok(fd) + })?; + Ok(Self(fd)) + } +} + +thread_local! { +static FD_SERIALIZATION_CTX: RefCell>> = RefCell::new(None); +static FD_DESERIALIZATION_CTX: RefCell>>> = RefCell::new(None); +} + +impl AsFd for ProtocolFd { + fn as_fd(&self) -> std::os::unix::prelude::BorrowedFd<'_> { + self.0.as_fd() + } +} +impl AsRawFd for ProtocolFd { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} +impl IntoRawFd for ProtocolFd { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw_fd() + } +} +impl From for ProtocolFd { + fn from(value: OwnedFd) -> Self { + Self(value) + } +} +impl From for OwnedFd { + fn from(value: ProtocolFd) -> OwnedFd { + value.0 + } +} diff --git a/wire/src/flex/mod.rs b/wire/src/flex/mod.rs index 2819adb..99c39fe 100644 --- a/wire/src/flex/mod.rs +++ b/wire/src/flex/mod.rs @@ -9,12 +9,14 @@ use serde::{ SerializeTupleStruct, SerializeTupleVariant, }, }; -use std::{fmt::Display, marker::PhantomData}; +use std::{fmt::Display, marker::PhantomData, os::fd::OwnedFd}; mod datamap; pub use datamap::*; pub use flexbuffers; +use crate::fd::{with_fd_deserialization_ctx, with_fd_serialization_ctx}; + #[derive(Debug, thiserror::Error)] pub enum FlexSerializeError { #[error("Map key is not a string!")] @@ -33,11 +35,16 @@ impl serde::ser::Error for FlexSerializeError { /// Serialize the given data into flexbuffers, stripping struct field names off /// and putting structs into vectors to save space and computation. -pub fn serialize(to_serialize: S) -> Result, FlexSerializeError> { - let mut fbb = flexbuffers::Builder::default(); - let fs = FlexSerializer { fbb: &mut fbb }; - to_serialize.serialize(fs)?; - Ok(fbb.take_buffer()) +/// This also allows serializing file descriptors. +pub fn serialize( + to_serialize: S, +) -> Result<(Vec, Vec), FlexSerializeError> { + with_fd_serialization_ctx(|| { + let mut fbb = flexbuffers::Builder::default(); + let fs = FlexSerializer { fbb: &mut fbb }; + to_serialize.serialize(fs)?; + Ok(fbb.take_buffer()) + }) } struct FlexSerializer<'b> { @@ -943,10 +950,16 @@ impl SerializeMap for FlexMapSerializer<'_> { /// because it strips the names off of struct fields, /// instead putting the values into vectors with the same /// order to save space and speed up deserialization. -pub fn deserialize<'a, T: Deserialize<'a>>(data: &'a [u8]) -> Result { - let root = flexbuffers::Reader::get_root(data)?; - let deserializer = FlexbuffersDeserializer(root); - T::deserialize(deserializer) +/// This also allows deserializing file descriptors. +pub fn deserialize<'a, T: Deserialize<'a>>( + data: &'a [u8], + fds: impl IntoIterator, +) -> Result { + with_fd_deserialization_ctx(fds.into_iter(), || { + let root = flexbuffers::Reader::get_root(data)?; + let deserializer = FlexbuffersDeserializer(root); + T::deserialize(deserializer) + }) } struct ReaderIteratorWrapper<'d>(ReaderIterator<&'d [u8]>); @@ -1229,9 +1242,9 @@ fn round_trip_flex_serialize() { test_struct: None, }; test_struct.test_struct = Some(Box::new(test_struct.clone())); - let serialized = serialize(test_struct.clone()).unwrap(); + let (serialized, fds) = serialize(test_struct.clone()).unwrap(); let flex = flexbuffers::Reader::get_root(serialized.as_slice()).unwrap(); println!("{flex}"); - let deserialized: TestStruct = deserialize(&serialized).unwrap(); + let deserialized: TestStruct = deserialize(&serialized, fds.into_iter()).unwrap(); assert_eq!(test_struct, deserialized, "Round trip lost data"); } diff --git a/wire/src/lib.rs b/wire/src/lib.rs index ac2b346..0b6bcd0 100644 --- a/wire/src/lib.rs +++ b/wire/src/lib.rs @@ -4,6 +4,7 @@ pub mod client; /// Standard creation of sockets for servers pub mod server; +pub mod fd; /// Message format flatbuffer pub mod message {