diff --git a/Cargo.lock b/Cargo.lock index 6dc42fa..0d92375 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -502,6 +502,15 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "crc32fast" version = "1.3.2" @@ -582,7 +591,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" dependencies = [ - "libloading 0.7.4", + "libloading 0.8.0", ] [[package]] @@ -1090,6 +1099,17 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +[[package]] +name = "kdl" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "062c875482ccb676fd40c804a40e3824d4464c18c364547456d1c8e8e951ae47" +dependencies = [ + "miette", + "nom", + "thiserror", +] + [[package]] name = "khronos_api" version = "3.1.0" @@ -1226,6 +1246,29 @@ dependencies = [ "autocfg", ] +[[package]] +name = "miette" +version = "5.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e" +dependencies = [ + "miette-derive", + "once_cell", + "thiserror", + "unicode-width", +] + +[[package]] +name = "miette-derive" +version = "5.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] + [[package]] name = "mime" version = "0.3.17" @@ -1616,9 +1659,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.67" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] @@ -2011,10 +2054,16 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "split-iter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f2b15926089e5526bb2dd738a2eb0e59034356e06eb71e1cd912358c0e62c4d" + [[package]] name = "stardust-xr" version = "0.14.1" -source = "git+https://github.com/StardustXR/core.git#975331f9739a9f6cb90ec75813b7720c86225848" +source = "git+https://github.com/StardustXR/core.git?branch=feat/idl#c7e27806c671d0ad262801583ec30acbf710a143" dependencies = [ "cluFlock", "color-rs", @@ -2034,11 +2083,12 @@ dependencies = [ [[package]] name = "stardust-xr-schemas" version = "1.5.3" -source = "git+https://github.com/StardustXR/core.git#975331f9739a9f6cb90ec75813b7720c86225848" +source = "git+https://github.com/StardustXR/core.git?branch=feat/idl#c7e27806c671d0ad262801583ec30acbf710a143" dependencies = [ "flatbuffers", "flexbuffers", "glam 0.24.2", + "kdl", "manifest-dir-macros", "mint", "ouroboros", @@ -2077,6 +2127,7 @@ dependencies = [ "serde_repr", "smithay", "stardust-xr", + "stardust-xr-server-codegen", "stereokit", "tokio", "tracing", @@ -2087,6 +2138,18 @@ dependencies = [ "xkbcommon", ] +[[package]] +name = "stardust-xr-server-codegen" +version = "0.1.0" +dependencies = [ + "convert_case", + "mint", + "proc-macro2", + "quote", + "split-iter", + "stardust-xr-schemas", +] + [[package]] name = "static_assertions" version = "1.1.0" @@ -2446,6 +2509,18 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + [[package]] name = "utf8parse" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index 68342dc..ecfa40b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,9 @@ license = "GPLv2" repository = "https://github.com/StardustXR/stardust-xr-server/" homepage = "https://stardustxr.org" +[workspace] +members = ["codegen"] + [[bin]] name = "stardust-xr-server" path = "src/main.rs" @@ -98,6 +101,10 @@ optional = true [dependencies.stardust-xr] git = "https://github.com/StardustXR/core.git" +branch = "feat/idl" + +[dependencies.stardust-xr-server-codegen] +path = "codegen" # [patch.crates-io.stereokit] # path = "../stereokit-rs" diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml new file mode 100644 index 0000000..3fb3d9f --- /dev/null +++ b/codegen/Cargo.toml @@ -0,0 +1,18 @@ +[package] +edition = "2021" +name = "stardust-xr-server-codegen" +version = "0.1.0" + +[lib] +proc-macro = true + +[dependencies] +convert_case = "0.6.0" +quote = "1.0.33" +mint = "0.5.9" +proc-macro2 = "1.0.71" +split-iter = "0.1.0" + +[dependencies.stardust-xr-schemas] +git = "https://github.com/StardustXR/core.git" +branch = "feat/idl" diff --git a/codegen/src/lib.rs b/codegen/src/lib.rs new file mode 100644 index 0000000..1d233a3 --- /dev/null +++ b/codegen/src/lib.rs @@ -0,0 +1,610 @@ +use convert_case::{Case, Casing}; +use proc_macro2::{Ident, Span, TokenStream}; +use quote::{quote, ToTokens}; +use split_iter::Splittable; +use stardust_xr_schemas::protocol::*; + +fn fold_tokens(a: TokenStream, b: TokenStream) -> TokenStream { + quote!(#a #b) +} + +// #[proc_macro] +// pub fn codegen_root_protocol(_input: proc_macro::TokenStream) -> proc_macro::TokenStream { +// codegen_protocol(ROOT_PROTOCOL) +// } +#[proc_macro] +pub fn codegen_node_protocol(_input: proc_macro::TokenStream) -> proc_macro::TokenStream { + codegen_protocol(NODE_PROTOCOL) +} +#[proc_macro] +pub fn codegen_spatial_protocol(_input: proc_macro::TokenStream) -> proc_macro::TokenStream { + codegen_protocol(SPATIAL_PROTOCOL) +} +#[proc_macro] +pub fn codegen_field_protocol(_input: proc_macro::TokenStream) -> proc_macro::TokenStream { + codegen_protocol(FIELD_PROTOCOL) +} +#[proc_macro] +pub fn codegen_data_protocol(_input: proc_macro::TokenStream) -> proc_macro::TokenStream { + codegen_protocol(DATA_PROTOCOL) +} +#[proc_macro] +pub fn codegen_zone_protocol(_input: proc_macro::TokenStream) -> proc_macro::TokenStream { + codegen_protocol(ZONE_PROTOCOL) +} +#[proc_macro] +pub fn codegen_audio_protocol(_input: proc_macro::TokenStream) -> proc_macro::TokenStream { + codegen_protocol(AUDIO_PROTOCOL) +} +#[proc_macro] +pub fn codegen_drawable_protocol(_input: proc_macro::TokenStream) -> proc_macro::TokenStream { + codegen_protocol(DRAWABLE_PROTOCOL) +} +#[proc_macro] +pub fn codegen_drawable_lines_protocol(_input: proc_macro::TokenStream) -> proc_macro::TokenStream { + codegen_protocol(DRAWABLE_LINES_PROTOCOL) +} +#[proc_macro] +pub fn codegen_drawable_model_protocol(_input: proc_macro::TokenStream) -> proc_macro::TokenStream { + codegen_protocol(DRAWABLE_MODEL_PROTOCOL) +} +#[proc_macro] +pub fn codegen_drawable_text_protocol(_input: proc_macro::TokenStream) -> proc_macro::TokenStream { + codegen_protocol(DRAWABLE_TEXT_PROTOCOL) +} +// #[proc_macro] +// pub fn codegen_input_protocol(_input: proc_macro::TokenStream) -> proc_macro::TokenStream { +// codegen_protocol(INPUT_PROTOCOL) +// } + +fn codegen_protocol(protocol: &'static str) -> proc_macro::TokenStream { + let protocol = Protocol::parse(protocol).unwrap(); + let custom_enums = protocol + .custom_enums + .iter() + .map(generate_custom_enum) + .reduce(fold_tokens) + .unwrap_or_default(); + let custom_unions = protocol + .custom_unions + .iter() + .map(generate_custom_union) + .reduce(fold_tokens) + .unwrap_or_default(); + let custom_structs = protocol + .custom_structs + .iter() + .map(generate_custom_struct) + .reduce(fold_tokens) + .unwrap_or_default(); + // let aspects = protocol + // .aspects + // .iter() + // .map(generate_aspect) + // .reduce(fold_tokens) + // .unwrap_or_default(); + // let nodes = protocol + // .nodes + // .iter() + // .map(generate_node) + // .reduce(fold_tokens) + // .unwrap_or_default(); + // let interfaces = protocol + // .interfaces + // .iter() + // .map(generate_interface) + // .reduce(fold_tokens) + // .unwrap_or_default(); + // quote!(#custom_enums #custom_unions #custom_structs #aspects #nodes #interfaces).into() + quote!(#custom_enums #custom_unions #custom_structs).into() +} + +fn generate_custom_enum(custom_enum: &CustomEnum) -> TokenStream { + let name = Ident::new(&custom_enum.name.to_case(Case::Pascal), Span::call_site()); + let description = &custom_enum.description; + + let argument_decls = custom_enum + .variants + .iter() + .map(|a| Ident::new(&a.to_case(Case::Pascal), Span::call_site()).to_token_stream()) + .reduce(|a, b| quote!(#a, #b)) + .unwrap_or_default(); + + quote! { + #[doc = #description] + #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] + pub enum #name {#argument_decls} + } +} +fn generate_custom_union(custom_union: &CustomUnion) -> TokenStream { + let name = Ident::new(&custom_union.name.to_case(Case::Pascal), Span::call_site()); + let description = &custom_union.description; + + let option_decls = custom_union + .options + .iter() + .map(generate_union_option) + .reduce(|a, b| quote!(#a, #b)) + .unwrap_or_default(); + + quote! { + #[doc = #description] + #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] + #[serde(untagged)] + pub enum #name {#option_decls} + } +} +fn generate_union_option(union_option: &UnionOption) -> TokenStream { + let name = union_option + .name + .as_ref() + .map(|n| n.to_case(Case::Pascal)) + .unwrap_or_else(|| argument_type_option_name(&union_option._type)); + let description = union_option + .description + .as_ref() + .map(|d| quote!(#[doc = #d])) + .unwrap_or_default(); + let identifier = Ident::new(&name, Span::call_site()); + let _type = generate_argument_type(&union_option._type, true); + quote! (#description #identifier(#_type)) +} +fn argument_type_option_name(argument_type: &ArgumentType) -> String { + match argument_type { + ArgumentType::Bool => "Bool".to_string(), + ArgumentType::Int => "Int".to_string(), + ArgumentType::UInt => "UInt".to_string(), + ArgumentType::Float => "Float".to_string(), + ArgumentType::Vec2 => "Vec2".to_string(), + ArgumentType::Vec3 => "Vec3".to_string(), + ArgumentType::Quat => "Quat".to_string(), + ArgumentType::Color => "Color".to_string(), + ArgumentType::String => "String".to_string(), + ArgumentType::Bytes => "Bytes".to_string(), + ArgumentType::Vec(v) => format!("{}Vector", argument_type_option_name(&v)), + ArgumentType::Map(m) => format!("{}Map", argument_type_option_name(&m)), + ArgumentType::Datamap => "Datamap".to_string(), + ArgumentType::ResourceID => "ResourceID".to_string(), + ArgumentType::Enum(e) => e.clone(), + ArgumentType::Union(u) => u.clone(), + ArgumentType::Struct(s) => s.clone(), + ArgumentType::Node { _type, .. } => _type.clone(), + } +} +fn generate_custom_struct(custom_struct: &CustomStruct) -> TokenStream { + let name = Ident::new(&custom_struct.name.to_case(Case::Pascal), Span::call_site()); + let description = &custom_struct.description; + + let argument_decls = custom_struct + .fields + .iter() + .map(|a| generate_argument_decl(a, true)) + .reduce(|a, b| quote!(#a, #b)) + .unwrap_or_default(); + + quote! { + #[doc = #description] + #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] + pub struct #name {#argument_decls} + } +} + +fn generate_interface(interface: &Interface) -> TokenStream { + interface + .members + .iter() + .map(generate_member) + .reduce(fold_tokens) + .unwrap_or_default() +} + +fn generate_node(node: &Node) -> TokenStream { + let node_name = Ident::new(&node.name, Span::call_site()); + let description = &node.description; + + let aspects = node + .aspects + .iter() + .map(|a| { + let aspect_name = Ident::new(&format!("{a}Aspect"), Span::call_site()); + quote!(impl #aspect_name for #node_name {}) + }) + .reduce(fold_tokens) + .unwrap_or_default(); + + quote! { + #[doc = #description] + #[derive(Debug)] + pub struct #node_name (crate::node::Node); + impl crate::node::NodeType for #node_name { + fn node(&self) -> &crate::node::Node { + &self.0 + } + fn alias(&self) -> Self { + #node_name(self.0.alias()) + } + fn from_path(client: &std::sync::Arc, path: String, destroyable: bool) -> Self { + #node_name(crate::node::Node::from_path(client, path, destroyable)) + } + } + impl serde::Serialize for #node_name { + fn serialize(&self, serializer: S) -> Result { + let node_path = self.0.get_path().map_err(|e| serde::ser::Error::custom(e))?; + serializer.serialize_str(&node_path) + } + } + #aspects + } +} + +fn generate_aspect(aspect: &Aspect) -> TokenStream { + let description = &aspect.description; + let (client_members, server_members) = aspect.members.iter().split(|m| m.side == Side::Server); + + let aspect_handler_name = Ident::new( + &format!("{}Handler", &aspect.name.to_case(Case::Pascal)), + Span::call_site(), + ); + let client_side_members = client_members + .map(generate_member) + .reduce(fold_tokens) + .map(|t| { + quote! { + #[doc = #description] + pub trait #aspect_handler_name: Send + Sync + 'static { + #t + } + } + }) + .unwrap_or_default(); + let aspect_wrap = aspect + .members + .iter() + .filter(|m| m.side == Side::Client) + .map(generate_handler) + .reduce(fold_tokens).map(|handlers| { + quote! { + #[must_use = "Dropping this handler wrapper would immediately drop the handler"] + fn wrap(self, handler: H) -> NodeResult> { + self.wrap_raw(std::sync::Arc::new(parking_lot::Mutex::new(handler))) + } + #[must_use = "Dropping this handler wrapper would immediately drop the handler"] + fn wrap_raw(self, handler: std::sync::Arc>) -> NodeResult> { + let handler_wrapper = crate::HandlerWrapper::new_raw(self, handler); + #handlers + Ok(handler_wrapper) + } + } + }).unwrap_or_default(); + + let aspect_trait_name = Ident::new( + &format!("{}Aspect", &aspect.name.to_case(Case::Pascal)), + Span::call_site(), + ); + let server_side_members = server_members + .map(generate_member) + .reduce(fold_tokens) + .unwrap_or_default(); + let server_side_members = quote! { + #[doc = #description] + pub trait #aspect_trait_name: crate::node::NodeType { + #aspect_wrap + #server_side_members + } + }; + quote!(#client_side_members #server_side_members) +} + +fn generate_member(member: &Member) -> TokenStream { + let name_str = &member.name; + let name = Ident::new(&member.name.to_case(Case::Snake), Span::call_site()); + let description = &member.description; + + let side = member.side; + let _type = member._type; + + let first_arg = if member.interface_path.is_some() { + quote!(client: &std::sync::Arc) + } else { + if member.side == Side::Server { + quote!(&self) + } else { + quote!(&mut self) + } + }; + let argument_decls = member + .arguments + .iter() + .map(|a| generate_argument_decl(a, member.side == Side::Client)) + .fold(first_arg, |a, b| quote!(#a, #b)); + + let argument_uses = member + .arguments + .iter() + .map(|a| generate_argument_serialize(&a.name, &a._type, a.optional)) + .reduce(|a, b| quote!(#a, #b)) + .unwrap_or_default(); + let return_type = member + .return_type + .as_ref() + .map(|r| generate_argument_type(&r, true)) + .unwrap_or_else(|| quote!(())); + + match (side, _type) { + (Side::Server, MemberType::Method) => { + let body = if let Some(interface_path) = &member.interface_path { + quote! { + let data = stardust_xr::schemas::flex::serialize(&(#argument_uses))?; + let result = client.message_sender_handle.method(#interface_path, #name_str, &data, Vec::new())?.await?; + Ok(stardust_xr::schemas::flex::deserialize(&result.into_message())?) + } + } else { + quote! { + self.node().execute_remote_method(#name_str, &(#argument_uses)).await + } + }; + quote! { + #[doc = #description] + async fn #name(#argument_decls) -> crate::node::NodeResult<#return_type> { + #body + } + } + } + (Side::Server, MemberType::Signal) => { + let mut body = if let Some(interface_path) = &member.interface_path { + quote! { + client.message_sender_handle.signal(#interface_path, #name_str, &stardust_xr::schemas::flex::serialize(&(#argument_uses))?, Vec::new()) + } + } else { + quote! { + self.node().send_remote_signal(#name_str, &(#argument_uses)) + } + }; + body = if let Some(ArgumentType::Node { + _type: _, + return_info, + }) = &member.return_type + { + if let Some(return_info) = return_info { + let parent = &return_info.parent; + let name_argument = Ident::new(&return_info.name_argument, Span::call_site()); + let get_client = if member.interface_path.is_some() { + quote!(client) + } else { + quote!(self.node().client()?) + }; + quote! { + #body?; + Ok(<#return_type as crate::node::NodeType>::from_parent_name(#get_client, #parent, &#name_argument, true)) + } + } else { + quote! { + Ok(#body?) + } + } + } else { + quote! { + Ok(#body?) + } + }; + quote! { + #[doc = #description] + fn #name(#argument_decls) -> crate::node::NodeResult<#return_type> { + #body + } + } + } + (Side::Client, MemberType::Method) => { + quote! { + #[doc = #description] + fn #name(#argument_decls) -> crate::node::MethodResult<#return_type>; + } + } + (Side::Client, MemberType::Signal) => { + quote! { + #[doc = #description] + fn #name(#argument_decls); + } + } + } +} +fn generate_handler(member: &Member) -> TokenStream { + let name = &member.name; + let name_ident = Ident::new(&name, Span::call_site()); + + let argument_names = member + .arguments + .iter() + .map(generate_argument_name) + .reduce(|a, b| quote!(#a, #b)); + let argument_types = member + .arguments + .iter() + .map(|a| &a._type) + .map(convert_deserializeable_argument_type) + .map(|a| generate_argument_type(&a, true)) + .reduce(|a, b| quote!(#a, #b)); + // dbg!(&argument_types); + let deserialize = argument_names + .clone() + .zip(argument_types) + .map(|(argument_names, argument_types)| { + quote!(let (#argument_names): (#argument_types) = stardust_xr::schemas::flex::deserialize(_data)?;) + }) + .unwrap_or_default(); + let argument_uses = member + .arguments + .iter() + .map(|a| generate_argument_deserialize(&a.name, &a._type, a.optional)) + .fold(TokenStream::default(), |a, b| quote!(#a, #b)); + let handler_wrapper_method_name = match member._type { + MemberType::Signal => quote!(add_handled_signal), + MemberType::Method => quote!(add_handled_method), + }; + + quote! { + handler_wrapper.#handler_wrapper_method_name(#name, |_node, _handler, _data, _fds| { + #deserialize + let _client = _node.client()?; + let mut _handler_lock = _handler.lock(); + Ok(H::#name_ident(&mut *_handler_lock #argument_uses)) + })?; + } +} +fn generate_argument_name(argument: &Argument) -> TokenStream { + Ident::new(&argument.name.to_case(Case::Snake), Span::call_site()).to_token_stream() +} +fn generate_argument_deserialize( + argument_name: &str, + argument_type: &ArgumentType, + optional: bool, +) -> TokenStream { + let name = Ident::new(&argument_name.to_case(Case::Snake), Span::call_site()); + match argument_type { + ArgumentType::Node { + _type, + return_info: _, + } => { + let node_type = Ident::new(&_type.to_case(Case::Pascal), Span::call_site()); + match optional { + true => quote!(#name.map(|n| #node_type::from_path(&_client, n, false))), + false => quote!(#node_type::from_path(&_client, #name, false)), + } + } + ArgumentType::Color => quote!(color::rgba_linear!(#name[0], #name[1], #name[2], #name[3])), + ArgumentType::Vec(v) => { + let mapping = generate_argument_deserialize("a", v, false); + quote!(#name.iter().map(|a| Ok(#mapping)).collect::, crate::node::NodeError>>()?) + } + ArgumentType::Map(v) => { + let mapping = generate_argument_deserialize("a", v, false); + quote!(#name.iter().map(|(k, a)| Ok((k, #mapping))).collect::, crate::node::NodeError>>()?) + } + _ => quote!(#name), + } +} +fn convert_deserializeable_argument_type(argument_type: &ArgumentType) -> ArgumentType { + match argument_type { + ArgumentType::Node { .. } => ArgumentType::String, + f => f.clone(), + } +} + +fn generate_argument_serialize( + argument_name: &str, + argument_type: &ArgumentType, + optional: bool, +) -> TokenStream { + let name = Ident::new(&argument_name.to_case(Case::Snake), Span::call_site()); + match argument_type { + ArgumentType::Node { + _type, + return_info: _, + } => match optional { + true => quote!(#name.map(|n| n.node().get_path()).transpose()?), + false => quote!(#name.node().get_path()?), + }, + ArgumentType::Color => quote!([#name.c.r, #name.c.g, #name.c.b, #name.a]), + ArgumentType::Vec(v) => { + let mapping = generate_argument_serialize("a", v, false); + quote!(#name.iter().map(|a| Ok(#mapping)).collect::, crate::node::NodeError>>()?) + } + ArgumentType::Map(v) => { + let mapping = generate_argument_serialize("a", v, false); + quote!(#name.iter().map(|(k, a)| Ok((k, #mapping))).collect::, crate::node::NodeError>>()?) + } + _ => quote!(#name), + } +} +fn generate_argument_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>); + } + quote!(#name: #_type) +} +fn generate_argument_type(argument_type: &ArgumentType, owned: bool) -> TokenStream { + match argument_type { + ArgumentType::Bool => quote!(bool), + ArgumentType::Int => quote!(i32), + ArgumentType::UInt => quote!(u32), + ArgumentType::Float => quote!(f32), + ArgumentType::Vec2 => quote!(mint::Vector2), + ArgumentType::Vec3 => quote!(mint::Vector3), + ArgumentType::Quat => quote!(mint::Quaternion), + ArgumentType::Color => quote!(stardust_xr::values::Color), + ArgumentType::Bytes => { + if !owned { + quote!(&[u8]) + } else { + quote!(Vec) + } + } + ArgumentType::String => { + if !owned { + quote!(&str) + } else { + quote!(String) + } + } + ArgumentType::Vec(t) => { + let t = generate_argument_type(&t, true); + if !owned { + quote!(&[#t]) + } else { + quote!(Vec<#t>) + } + } + ArgumentType::Map(t) => { + let t = generate_argument_type(&t, true); + + if !owned { + quote!(&rustc_hash::FxHashMap) + } else { + quote!(rustc_hash::FxHashMap) + } + } + ArgumentType::Datamap => { + if !owned { + quote!(&stardust_xr::values::Datamap) + } else { + quote!(stardust_xr::values::Datamap) + } + } + ArgumentType::ResourceID => { + if !owned { + quote!(&stardust_xr::values::ResourceID) + } else { + quote!(stardust_xr::values::ResourceID) + } + } + ArgumentType::Enum(e) => { + let enum_name = Ident::new(&e.to_case(Case::Pascal), Span::call_site()); + quote!(#enum_name) + } + ArgumentType::Union(u) => { + let union_name = Ident::new(&u.to_case(Case::Pascal), Span::call_site()); + quote!(#union_name) + } + ArgumentType::Struct(s) => { + let struct_name = Ident::new(&s.to_case(Case::Pascal), Span::call_site()); + quote!(#struct_name) + } + ArgumentType::Node { + _type, + return_info: _, + } => { + if !owned { + let aspect = Ident::new( + &format!("{}Aspect", _type.to_case(Case::Pascal)), + Span::call_site(), + ); + quote!(&impl #aspect) + } else { + let node = Ident::new(&_type.to_case(Case::Pascal), Span::call_site()); + quote!(#node) + } + } + } +} diff --git a/src/core/mod.rs b/src/core/mod.rs index e2910d1..71862d3 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -8,4 +8,3 @@ pub mod registry; pub mod resource; pub mod scenegraph; pub mod task; -pub mod typed_datamap; diff --git a/src/core/typed_datamap.rs b/src/core/typed_datamap.rs deleted file mode 100644 index 4f42f90..0000000 --- a/src/core/typed_datamap.rs +++ /dev/null @@ -1,56 +0,0 @@ -#![allow(unused)] - -use std::ops::{Deref, DerefMut}; - -use color_eyre::eyre::Result; -use once_cell::sync::Lazy; -use serde::{de::DeserializeOwned, Serialize}; -use stardust_xr::schemas::{ - flat::Datamap, - flex::flexbuffers::{FlexbufferSerializer, Reader, ReaderError}, -}; - -use crate::nodes::Message; - -pub struct TypedDatamap(T); -impl TypedDatamap { - pub fn new(data: T) -> Self { - TypedDatamap(data) - } - pub fn from_flex(message: Message) -> Result { - let root = Reader::get_root(message.as_ref())?; - T::deserialize(root).map(Self::new).map_err(|e| e.into()) - } - pub fn to_datamap(&mut self) -> Result { - let mut serializer = FlexbufferSerializer::default(); - self.0.serialize(&mut serializer)?; - Datamap::new(serializer.take_buffer()).map_err(|e| e.into()) - } - pub fn serialize(&mut self) -> Option> { - let mut serializer = FlexbufferSerializer::default(); - self.0.serialize(&mut serializer).ok()?; - // check if this is actually a map - Reader::get_root(serializer.view()).ok()?.get_map().ok()?; - Some(serializer.take_buffer()) - } -} -impl Default for TypedDatamap -where - T: Default, -{ - fn default() -> Self { - Self(T::default()) - } -} -impl Deref for TypedDatamap { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} -impl DerefMut for TypedDatamap { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} diff --git a/src/nodes/audio.rs b/src/nodes/audio.rs index 7bedbcd..c89e508 100644 --- a/src/nodes/audio.rs +++ b/src/nodes/audio.rs @@ -3,7 +3,7 @@ use crate::core::client::Client; use crate::core::destroy_queue; use crate::core::registry::Registry; use crate::core::resource::ResourceID; -use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial}; +use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial, Transform}; use color_eyre::eyre::{ensure, eyre, Result}; use glam::{vec3, Vec4Swizzles}; use once_cell::sync::OnceCell; @@ -11,7 +11,7 @@ use parking_lot::Mutex; use send_wrapper::SendWrapper; use serde::Deserialize; use stardust_xr::schemas::flex::deserialize; -use stardust_xr::values::Transform; + use std::ops::DerefMut; use std::{ffi::OsStr, path::PathBuf, sync::Arc}; use stereokit::{Sound as SkSound, SoundInstance, StereoKitDraw}; diff --git a/src/nodes/data.rs b/src/nodes/data.rs index 02f8129..c980970 100644 --- a/src/nodes/data.rs +++ b/src/nodes/data.rs @@ -7,7 +7,7 @@ use crate::core::node_collections::LifeLinkedNodeMap; use crate::core::registry::Registry; use crate::core::scenegraph::MethodResponseSender; use crate::nodes::fields::{find_field, FIELD_ALIAS_INFO}; -use crate::nodes::spatial::find_spatial_parent; +use crate::nodes::spatial::{find_spatial_parent, Transform}; use color_eyre::eyre::{bail, ensure, eyre, Result}; use glam::vec3a; use lazy_static::lazy_static; @@ -17,7 +17,7 @@ use parking_lot::Mutex; use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; use stardust_xr::schemas::flex::{deserialize, flexbuffers, serialize}; -use stardust_xr::values::Transform; + use std::fmt::Display; use std::sync::{Arc, Weak}; @@ -111,9 +111,15 @@ impl PulseSender { if !mask_matches(&self.mask, &receiver.mask) { return; } - let Some(tx_node) = self.node.upgrade() else {return}; - let Some(tx_client) = tx_node.get_client() else {return}; - let Some(rx_node) = receiver.node.upgrade() else {return}; + let Some(tx_node) = self.node.upgrade() else { + return; + }; + let Some(tx_client) = tx_node.get_client() else { + return; + }; + let Some(rx_node) = receiver.node.upgrade() else { + return; + }; // Receiver itself let rx_alias = Alias::create( &tx_client, @@ -167,7 +173,7 @@ impl PulseSender { rotation: rotation.into(), }; - let Ok(data) = serialize(info) else {return}; + let Ok(data) = serialize(info) else { return }; let _ = tx_node.send_remote_signal("new_receiver", data); } @@ -175,8 +181,10 @@ impl PulseSender { let uid = receiver.uid.as_str(); self.aliases.remove(uid); self.aliases.remove(&(uid.to_string() + "-field")); - let Some(tx_node) = self.node.upgrade() else {return}; - let Ok(data) = serialize(&uid) else {return}; + let Some(tx_node) = self.node.upgrade() else { + return; + }; + let Ok(data) = serialize(&uid) else { return }; let _ = tx_node.send_remote_signal("drop_receiver", data); } @@ -348,7 +356,9 @@ pub fn get_keymap_flex( response.wrap_sync(move || { let keymap_id: &str = deserialize(message.as_ref())?; let keymaps = KEYMAPS.lock(); - let Some(keymap) = keymaps.get(keymap_id) else {bail!("Could not find keymap. Try registering it")}; + let Some(keymap) = keymaps.get(keymap_id) else { + bail!("Could not find keymap. Try registering it") + }; Ok(serialize(keymap)?.into()) }); diff --git a/src/nodes/drawable/lines.rs b/src/nodes/drawable/lines.rs index 8318bb2..8e25e10 100644 --- a/src/nodes/drawable/lines.rs +++ b/src/nodes/drawable/lines.rs @@ -1,7 +1,7 @@ use crate::{ core::{client::Client, registry::Registry}, nodes::{ - spatial::{find_spatial_parent, parse_transform, Spatial}, + spatial::{find_spatial_parent, parse_transform, Spatial, Transform}, Message, Node, }, }; @@ -12,7 +12,7 @@ use parking_lot::Mutex; use portable_atomic::{AtomicBool, Ordering}; use prisma::{Flatten, Lerp, Rgba}; use serde::Deserialize; -use stardust_xr::{schemas::flex::deserialize, values::Transform}; +use stardust_xr::schemas::flex::deserialize; use std::{collections::VecDeque, sync::Arc}; use stereokit::{bounds_grow_to_fit_pt, Bounds, Color128, LinePoint as SkLinePoint, StereoKitDraw}; diff --git a/src/nodes/drawable/model.rs b/src/nodes/drawable/model.rs index 929b22b..f6c2785 100644 --- a/src/nodes/drawable/model.rs +++ b/src/nodes/drawable/model.rs @@ -4,7 +4,7 @@ use crate::core::node_collections::LifeLinkedNodeMap; use crate::core::registry::Registry; use crate::core::resource::ResourceID; use crate::nodes::drawable::Drawable; -use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial}; +use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial, Transform}; use crate::nodes::Message; use crate::SK_MULTITHREAD; use color_eyre::eyre::{bail, ensure, eyre, Result}; @@ -16,7 +16,7 @@ use portable_atomic::{AtomicBool, Ordering}; use rustc_hash::FxHashMap; use serde::Deserialize; use stardust_xr::schemas::flex::deserialize; -use stardust_xr::values::Transform; + use std::ffi::OsStr; use std::path::PathBuf; use std::sync::{Arc, Weak}; diff --git a/src/nodes/drawable/text.rs b/src/nodes/drawable/text.rs index 2c2c214..8084285 100644 --- a/src/nodes/drawable/text.rs +++ b/src/nodes/drawable/text.rs @@ -2,7 +2,7 @@ use crate::{ core::{client::Client, destroy_queue, registry::Registry, resource::ResourceID}, nodes::{ drawable::Drawable, - spatial::{find_spatial_parent, parse_transform, Spatial}, + spatial::{find_spatial_parent, parse_transform, Spatial, Transform}, Message, Node, }, }; @@ -14,7 +14,7 @@ use parking_lot::Mutex; use portable_atomic::{AtomicBool, Ordering}; use prisma::{Flatten, Rgba}; use serde::Deserialize; -use stardust_xr::{schemas::flex::deserialize, values::Transform}; +use stardust_xr::schemas::flex::deserialize; use std::{ffi::OsStr, path::PathBuf, sync::Arc}; use stereokit::{named_colors::WHITE, Color128, StereoKitDraw, TextAlign, TextFit, TextStyle}; @@ -150,7 +150,9 @@ impl Text { _calling_client: Arc, message: Message, ) -> Result<()> { - let Some(Drawable::Text(text)) = node.drawable.get() else {bail!("Not a drawable??")}; + let Some(Drawable::Text(text)) = node.drawable.get() else { + bail!("Not a drawable??") + }; text.data.lock().character_height = deserialize(message.as_ref())?; Ok(()) @@ -161,7 +163,9 @@ impl Text { _calling_client: Arc, message: Message, ) -> Result<()> { - let Some(Drawable::Text(text)) = node.drawable.get() else {bail!("Not a drawable??")}; + let Some(Drawable::Text(text)) = node.drawable.get() else { + bail!("Not a drawable??") + }; text.data.lock().text = deserialize(message.as_ref())?; Ok(()) diff --git a/src/nodes/fields/box.rs b/src/nodes/fields/box.rs index 130a4ce..31872dd 100644 --- a/src/nodes/fields/box.rs +++ b/src/nodes/fields/box.rs @@ -1,6 +1,6 @@ use super::{Field, FieldTrait, Node}; use crate::core::client::Client; -use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial}; +use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial, Transform}; use crate::nodes::Message; use color_eyre::eyre::{ensure, Result}; use glam::{vec3, vec3a, Vec3, Vec3A}; @@ -8,7 +8,7 @@ use mint::Vector3; use parking_lot::Mutex; use serde::Deserialize; use stardust_xr::schemas::flex::deserialize; -use stardust_xr::values::Transform; + use std::sync::Arc; pub struct BoxField { @@ -46,7 +46,9 @@ impl BoxField { _calling_client: Arc, message: Message, ) -> Result<()> { - let Field::Box(box_field) = node.field.get().unwrap().as_ref() else { return Ok(()) }; + let Field::Box(box_field) = node.field.get().unwrap().as_ref() else { + return Ok(()); + }; box_field.set_size(deserialize(message.as_ref())?); Ok(()) diff --git a/src/nodes/fields/cylinder.rs b/src/nodes/fields/cylinder.rs index 8a0733e..e23658a 100644 --- a/src/nodes/fields/cylinder.rs +++ b/src/nodes/fields/cylinder.rs @@ -1,13 +1,12 @@ use super::{Field, FieldTrait, Node}; use crate::core::client::Client; -use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial}; +use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial, Transform}; use crate::nodes::Message; use color_eyre::eyre::{ensure, Result}; use glam::{swizzles::*, vec2, Vec3A}; use portable_atomic::AtomicF32; use serde::Deserialize; use stardust_xr::schemas::flex::deserialize; -use stardust_xr::values::Transform; use std::sync::atomic::Ordering; use std::sync::Arc; @@ -49,7 +48,9 @@ impl CylinderField { _calling_client: Arc, message: Message, ) -> Result<()> { - let Field::Cylinder(cylinder_field) = node.field.get().unwrap().as_ref() else { return Ok(()) }; + let Field::Cylinder(cylinder_field) = node.field.get().unwrap().as_ref() else { + return Ok(()); + }; let (length, radius) = deserialize(message.as_ref())?; cylinder_field.set_size(length, radius); Ok(()) diff --git a/src/nodes/fields/torus.rs b/src/nodes/fields/torus.rs index 8277706..587576d 100644 --- a/src/nodes/fields/torus.rs +++ b/src/nodes/fields/torus.rs @@ -1,13 +1,12 @@ use super::{Field, FieldTrait, Node}; use crate::core::client::Client; -use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial}; +use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial, Transform}; use crate::nodes::Message; use color_eyre::eyre::{ensure, Result}; use glam::{swizzles::*, vec2, Vec3A}; use portable_atomic::AtomicF32; use serde::Deserialize; use stardust_xr::schemas::flex::deserialize; -use stardust_xr::values::Transform; use std::sync::atomic::Ordering; use std::sync::Arc; @@ -49,7 +48,9 @@ impl TorusField { _calling_client: Arc, message: Message, ) -> Result<()> { - let Field::Torus(torus_field) = node.field.get().unwrap().as_ref() else { return Ok(()) }; + let Field::Torus(torus_field) = node.field.get().unwrap().as_ref() else { + return Ok(()); + }; let (radius_a, radius_b) = deserialize(message.as_ref())?; torus_field.set_size(radius_a, radius_b); diff --git a/src/nodes/input/mod.rs b/src/nodes/input/mod.rs index c38f4a0..e3a363e 100644 --- a/src/nodes/input/mod.rs +++ b/src/nodes/input/mod.rs @@ -12,20 +12,19 @@ use super::{ spatial::{find_spatial_parent, parse_transform, Spatial}, Message, Node, }; -use crate::core::registry::Registry; use crate::core::{client::Client, node_collections::LifeLinkedNodeMap}; +use crate::{core::registry::Registry, nodes::spatial::Transform}; use color_eyre::eyre::{ensure, Result}; use glam::Mat4; use once_cell::sync::OnceCell; use parking_lot::Mutex; use portable_atomic::AtomicBool; use serde::Deserialize; -use stardust_xr::schemas::{flat::InputData, flex::deserialize}; -use stardust_xr::schemas::{ - flat::{Datamap, InputDataType}, - flex::serialize, +use stardust_xr::schemas::{flat::InputDataType, flex::serialize}; +use stardust_xr::{ + schemas::{flat::InputData, flex::deserialize}, + values::Datamap, }; -use stardust_xr::values::Transform; use std::ops::Deref; use std::sync::atomic::Ordering; use std::sync::{Arc, Weak}; @@ -119,7 +118,10 @@ impl InputMethod { } fn set_datamap_flex(node: &Node, _calling_client: Arc, message: Message) -> Result<()> { let method = InputMethod::get(node)?; - method.datamap.lock().replace(Datamap::new(message.data)?); + method + .datamap + .lock() + .replace(Datamap::from_raw(message.data)?); Ok(()) } fn set_handlers_flex(node: &Node, calling_client: Arc, message: Message) -> Result<()> { @@ -139,9 +141,15 @@ impl InputMethod { } fn make_alias(&self, handler: &InputHandler) { - let Some(method_node) = self.node.upgrade() else {return}; - let Some(handler_node) = handler.node.upgrade() else {return}; - let Some(client) = handler_node.get_client() else {return}; + let Some(method_node) = self.node.upgrade() else { + return; + }; + let Some(handler_node) = handler.node.upgrade() else { + return; + }; + let Some(client) = handler_node.get_client() else { + return; + }; let Ok(method_alias) = Alias::create( &client, handler_node.get_path(), @@ -151,7 +159,9 @@ impl InputMethod { server_signals: vec!["capture"], ..Default::default() }, - ) else {return}; + ) else { + return; + }; method_alias.enabled.store(false, Ordering::Relaxed); handler .method_aliases @@ -168,9 +178,15 @@ impl InputMethod { } fn handle_new_handler(&self, handler: &InputHandler) { - let Some(method_node) = self.node.upgrade() else {return}; - let Some(method_client) = method_node.get_client() else {return}; - let Some(handler_node) = handler.node.upgrade() else {return}; + let Some(method_node) = self.node.upgrade() else { + return; + }; + let Some(method_client) = method_node.get_client() else { + return; + }; + let Some(handler_node) = handler.node.upgrade() else { + return; + }; // Receiver itself let Ok(handler_alias) = Alias::create( &method_client, @@ -181,32 +197,40 @@ impl InputMethod { server_methods: vec!["getTransform"], ..Default::default() }, - ) else {return}; + ) else { + return; + }; self.handler_aliases .add(handler.uid.clone(), &handler_alias); if let Some(handler_field_node) = handler.field.spatial_ref().node.upgrade() { // Handler's field let Ok(rx_field_alias) = Alias::create( - &method_client, - handler_alias.get_path(), - "field", - &handler_field_node, - FIELD_ALIAS_INFO.clone(), - ) else {return}; + &method_client, + handler_alias.get_path(), + "field", + &handler_field_node, + FIELD_ALIAS_INFO.clone(), + ) else { + return; + }; self.handler_aliases .add(handler.uid.clone() + "-field", &rx_field_alias); } - let Ok(data) = serialize(&handler.uid) else {return}; + let Ok(data) = serialize(&handler.uid) else { + return; + }; let _ = method_node.send_remote_signal("handler_created", data); } fn handle_drop_handler(&self, handler: &InputHandler) { let uid = handler.uid.as_str(); self.handler_aliases.remove(uid); self.handler_aliases.remove(&(uid.to_string() + "-field")); - let Some(tx_node) = self.node.upgrade() else {return}; - let Ok(data) = serialize(&uid) else {return}; + let Some(tx_node) = self.node.upgrade() else { + return; + }; + let Ok(data) = serialize(&uid) else { return }; let _ = tx_node.send_remote_signal("handler_destroyed", data); } } @@ -299,7 +323,9 @@ impl InputHandler { distance_link: &DistanceLink, datamap: Datamap, ) { - let Some(node) = self.node.upgrade() else {return}; + let Some(node) = self.node.upgrade() else { + return; + }; let _ = node.send_remote_signal("input", distance_link.serialize(order, captured, datamap)); } } diff --git a/src/nodes/input/pointer.rs b/src/nodes/input/pointer.rs index f9148f5..5eb58c7 100644 --- a/src/nodes/input/pointer.rs +++ b/src/nodes/input/pointer.rs @@ -2,13 +2,14 @@ use super::{DistanceLink, InputSpecialization}; use crate::core::client::Client; use crate::nodes::fields::{Field, Ray, RayMarchResult}; use crate::nodes::input::{InputMethod, InputType}; -use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial}; +use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial, Transform}; use crate::nodes::{Message, Node}; use glam::{vec3, Mat4}; use serde::Deserialize; -use stardust_xr::schemas::flat::{Datamap, InputDataType, Pointer as FlatPointer}; +use stardust_xr::schemas::flat::{InputDataType, Pointer as FlatPointer}; use stardust_xr::schemas::flex::deserialize; -use stardust_xr::values::Transform; +use stardust_xr::values::Datamap; + use std::sync::Arc; #[derive(Default)] @@ -86,7 +87,8 @@ pub fn create_pointer_flex( InputMethod::add_to( &node, InputType::Pointer(Pointer), - info.datamap.and_then(|datamap| Datamap::new(datamap).ok()), + info.datamap + .and_then(|datamap| Datamap::from_raw(datamap).ok()), )?; Ok(()) } diff --git a/src/nodes/input/tip.rs b/src/nodes/input/tip.rs index 484c61f..e6395d5 100644 --- a/src/nodes/input/tip.rs +++ b/src/nodes/input/tip.rs @@ -2,14 +2,15 @@ use super::{DistanceLink, InputSpecialization}; use crate::core::client::Client; use crate::nodes::fields::Field; use crate::nodes::input::{InputMethod, InputType}; -use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial}; +use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial, Transform}; use crate::nodes::{Message, Node}; use color_eyre::eyre::Result; use glam::{vec3a, Mat4}; use serde::Deserialize; -use stardust_xr::schemas::flat::{Datamap, InputDataType, Tip as FlatTip}; +use stardust_xr::schemas::flat::{InputDataType, Tip as FlatTip}; use stardust_xr::schemas::flex::deserialize; -use stardust_xr::values::Transform; +use stardust_xr::values::Datamap; + use std::sync::Arc; #[derive(Default)] @@ -66,7 +67,8 @@ pub fn create_tip_flex(_node: &Node, calling_client: Arc, message: Messa InputType::Tip(Tip { radius: info.radius, }), - info.datamap.and_then(|datamap| Datamap::new(datamap).ok()), + info.datamap + .and_then(|datamap| Datamap::from_raw(datamap).ok()), )?; node.add_local_signal("set_radius", Tip::set_radius); Ok(()) diff --git a/src/nodes/items/camera.rs b/src/nodes/items/camera.rs index 0eb9b76..3c51c1e 100644 --- a/src/nodes/items/camera.rs +++ b/src/nodes/items/camera.rs @@ -8,7 +8,7 @@ use crate::{ nodes::{ drawable::{model::ModelPart, shaders::UNLIT_SHADER_BYTES, Drawable}, items::TypeInfo, - spatial::{find_spatial_parent, parse_transform, Spatial}, + spatial::{find_spatial_parent, parse_transform, Spatial, Transform}, Message, Node, }, }; @@ -20,10 +20,7 @@ use nanoid::nanoid; use once_cell::sync::OnceCell; use parking_lot::Mutex; use serde::Deserialize; -use stardust_xr::{ - schemas::flex::{deserialize, serialize}, - values::Transform, -}; +use stardust_xr::schemas::flex::{deserialize, serialize}; use std::sync::Arc; use stereokit::{ Color128, Material, Rect, RenderLayer, StereoKitDraw, Tex, TextureType, Transparency, @@ -87,7 +84,7 @@ impl CameraItem { ) { response.wrap_sync(move || { let ItemType::Camera(_camera) = &node.item.get().unwrap().specialization else { - return Err(eyre!("Wrong item type?")) + return Err(eyre!("Wrong item type?")); }; Ok(serialize(())?.into()) }); @@ -103,7 +100,11 @@ impl CameraItem { }; let model_part_node = calling_client.get_node("Model part", deserialize(&message.data).unwrap())?; - let Drawable::ModelPart(model_part) = model_part_node.get_aspect("Model part", "model part", |n| &n.drawable)? else {bail!("Drawable is not a model node")}; + let Drawable::ModelPart(model_part) = + model_part_node.get_aspect("Model part", "model part", |n| &n.drawable)? + else { + bail!("Drawable is not a model node") + }; camera.applied_to.add_raw(model_part); camera.apply_to.add_raw(model_part); Ok(()) @@ -155,7 +156,9 @@ impl CameraItem { pub fn update(sk: &impl StereoKitDraw) { for camera in ITEM_TYPE_INFO_CAMERA.items.get_valid_contents() { - let ItemType::Camera(camera) = &camera.specialization else {continue}; + let ItemType::Camera(camera) = &camera.specialization else { + continue; + }; camera.update(sk); } } diff --git a/src/nodes/items/environment.rs b/src/nodes/items/environment.rs index c2566cb..f753e01 100644 --- a/src/nodes/items/environment.rs +++ b/src/nodes/items/environment.rs @@ -7,7 +7,7 @@ use crate::{ }, nodes::{ items::TypeInfo, - spatial::{find_spatial_parent, parse_transform, Spatial}, + spatial::{find_spatial_parent, parse_transform, Spatial, Transform}, Message, Node, }, }; @@ -15,10 +15,7 @@ use color_eyre::eyre::{eyre, Result}; use lazy_static::lazy_static; use nanoid::nanoid; use serde::Deserialize; -use stardust_xr::{ - schemas::flex::{deserialize, serialize}, - values::Transform, -}; +use stardust_xr::schemas::flex::{deserialize, serialize}; use std::sync::Arc; lazy_static! { @@ -54,9 +51,10 @@ impl EnvironmentItem { response: MethodResponseSender, ) { response.wrap_sync(move || { - let ItemType::Environment(environment_item) = &node.item.get().unwrap().specialization else { - return Err(eyre!("Wrong item type?")) - }; + let ItemType::Environment(environment_item) = &node.item.get().unwrap().specialization + else { + return Err(eyre!("Wrong item type?")); + }; Ok(serialize(environment_item.path.as_str())?.into()) }); } diff --git a/src/nodes/items/mod.rs b/src/nodes/items/mod.rs index 75b9657..3465811 100644 --- a/src/nodes/items/mod.rs +++ b/src/nodes/items/mod.rs @@ -13,6 +13,7 @@ use crate::core::node_collections::LifeLinkedNodeMap; use crate::core::registry::Registry; use crate::nodes::alias::AliasInfo; use crate::nodes::fields::find_field; +use crate::nodes::spatial::Transform; use color_eyre::eyre::{ensure, eyre, Result}; use lazy_static::lazy_static; use nanoid::nanoid; @@ -20,7 +21,7 @@ use parking_lot::Mutex; use portable_atomic::Ordering; use serde::Deserialize; use stardust_xr::schemas::flex::{deserialize, serialize}; -use stardust_xr::values::Transform; + use std::hash::Hash; use std::sync::{Arc, Weak}; @@ -230,7 +231,9 @@ impl ItemUI { Ok(()) } fn send_state(&self, state: &str, name: &str) { - let Ok(serialized_data) = serialize(name) else {return}; + let Ok(serialized_data) = serialize(name) else { + return; + }; let _ = self .node .upgrade() @@ -239,14 +242,20 @@ impl ItemUI { } fn handle_create_item(&self, item: &Item) { - let Some(node) = self.node.upgrade() else {return}; - let Some(client) = node.get_client() else {return}; + let Some(node) = self.node.upgrade() else { + return; + }; + let Some(client) = node.get_client() else { + return; + }; if let Ok(alias_node) = item.make_alias(&client, &(node.get_path().to_string() + "/item")) { self.item_aliases.add(item.uid.clone(), &alias_node); } - let Ok(serialized_data) = item.specialization.serialize_start_data(&item.uid) else {return}; + let Ok(serialized_data) = item.specialization.serialize_start_data(&item.uid) else { + return; + }; let _ = node.send_remote_signal("create_item", serialized_data); } fn handle_destroy_item(&self, item: &Item) { @@ -254,29 +263,45 @@ impl ItemUI { self.send_state("destroy_item", item.uid.as_str()); } fn handle_capture_item(&self, item: &Item, acceptor: &ItemAcceptor) { - let Some(node) = self.node.upgrade() else {return}; + let Some(node) = self.node.upgrade() else { + return; + }; - let Ok(message) = serialize((item.uid.as_str(), acceptor.uid.as_str())) else {return}; + let Ok(message) = serialize((item.uid.as_str(), acceptor.uid.as_str())) else { + return; + }; let _ = node.send_remote_signal("capture_item", message); } fn handle_release_item(&self, item: &Item, acceptor: &ItemAcceptor) { - let Some(node) = self.node.upgrade() else {return}; + let Some(node) = self.node.upgrade() else { + return; + }; - let Ok(message) = serialize((item.uid.as_str(), acceptor.uid.as_str())) else {return}; + let Ok(message) = serialize((item.uid.as_str(), acceptor.uid.as_str())) else { + return; + }; let _ = node.send_remote_signal("release_item", message); } fn handle_create_acceptor(&self, acceptor: &ItemAcceptor) { - let Some(node) = self.node.upgrade() else {return}; - let Some(client) = node.get_client() else {return}; + let Some(node) = self.node.upgrade() else { + return; + }; + let Some(client) = node.get_client() else { + return; + }; let Ok((alias, field_alias)) = acceptor.make_aliases( &client, &format!("/item/{}/acceptor", self.type_info.type_name), - ) else {return}; + ) else { + return; + }; self.acceptor_aliases.add(acceptor.uid.clone(), &alias); self.acceptor_field_aliases .add(acceptor.uid.clone(), &field_alias); - let Ok(message) = serialize(&acceptor.uid) else {return}; + let Ok(message) = serialize(&acceptor.uid) else { + return; + }; let _ = node.send_remote_signal("create_acceptor", message); } fn handle_destroy_acceptor(&self, acceptor: &ItemAcceptor) { @@ -354,23 +379,33 @@ impl ItemAcceptor { Ok((acceptor_alias, acceptor_field_alias)) } fn handle_capture(&self, item: &Arc) { - let Some(node) = self.node.upgrade() else {return}; - let Some(client) = node.get_client() else {return}; + let Some(node) = self.node.upgrade() else { + return; + }; + let Some(client) = node.get_client() else { + return; + }; self.accepted_registry.add_raw(item); if let Ok(alias_node) = item.make_alias(&client, &node.path) { self.accepted_aliases.add(item.uid.clone(), &alias_node); } - let Ok(serialized_data) = item.specialization.serialize_start_data(&item.uid) else {return}; + let Ok(serialized_data) = item.specialization.serialize_start_data(&item.uid) else { + return; + }; let _ = node.send_remote_signal("capture", serialized_data); } fn handle_release(&self, item: &Item) { - let Some(node) = self.node.upgrade() else {return}; + let Some(node) = self.node.upgrade() else { + return; + }; self.accepted_registry.remove(item); self.accepted_aliases.remove(&item.uid); - let Ok(message) = serialize(&item.uid) else {return}; + let Ok(message) = serialize(&item.uid) else { + return; + }; let _ = node.send_remote_signal("release", message); } } diff --git a/src/nodes/spatial/mod.rs b/src/nodes/spatial/mod.rs index 0eb565e..cfa88a2 100644 --- a/src/nodes/spatial/mod.rs +++ b/src/nodes/spatial/mod.rs @@ -13,12 +13,13 @@ use once_cell::sync::OnceCell; use parking_lot::Mutex; use serde::Deserialize; use stardust_xr::schemas::flex::{deserialize, serialize}; -use stardust_xr::values::Transform; use std::fmt::Debug; use std::ptr; use std::sync::{Arc, Weak}; use stereokit::{bounds_grow_to_fit_box, Bounds}; +stardust_xr_server_codegen::codegen_spatial_protocol!(); + static ZONEABLE_REGISTRY: Registry = Registry::new(); pub struct Spatial { @@ -143,7 +144,7 @@ impl Spatial { let (mut reference_space_scl, mut reference_space_rot, mut reference_space_pos) = local_transform_in_reference_space.to_scale_rotation_translation(); - if let Some(pos) = transform.position { + if let Some(pos) = transform.translation { reference_space_pos = pos.into() } if let Some(rot) = transform.rotation { @@ -467,7 +468,7 @@ impl Drop for Spatial { pub fn parse_transform(transform: Transform, position: bool, rotation: bool, scale: bool) -> Mat4 { let position = position - .then_some(transform.position) + .then_some(transform.translation) .flatten() .unwrap_or_else(|| Vector3::from([0.0; 3])); let rotation = rotation diff --git a/src/nodes/spatial/zone.rs b/src/nodes/spatial/zone.rs index d236185..f163a53 100644 --- a/src/nodes/spatial/zone.rs +++ b/src/nodes/spatial/zone.rs @@ -4,7 +4,7 @@ use crate::{ nodes::{ alias::{Alias, AliasInfo}, fields::{find_field, Field}, - spatial::{find_spatial_parent, parse_transform}, + spatial::{find_spatial_parent, parse_transform, Transform}, Message, Node, }, }; @@ -13,10 +13,7 @@ use glam::vec3a; use parking_lot::Mutex; use rustc_hash::FxHashMap; use serde::Deserialize; -use stardust_xr::{ - schemas::flex::{deserialize, serialize}, - values::Transform, -}; +use stardust_xr::schemas::flex::{deserialize, serialize}; use std::sync::{Arc, Weak}; pub fn capture(spatial: &Arc, zone: &Arc) { @@ -31,8 +28,12 @@ pub fn capture(spatial: &Arc, zone: &Arc) { *spatial.old_parent.lock() = spatial.get_parent(); *spatial.zone.lock() = Arc::downgrade(zone); zone.captured.add_raw(spatial); - let Some(node) = zone.spatial.node.upgrade() else {return}; - let Ok(message) = serialize(&spatial.uid) else {return}; + let Some(node) = zone.spatial.node.upgrade() else { + return; + }; + let Ok(message) = serialize(&spatial.uid) else { + return; + }; let _ = node.send_remote_signal("capture", message); } } @@ -40,9 +41,13 @@ pub fn release(spatial: &Spatial) { let _ = spatial.set_spatial_parent_in_place(spatial.old_parent.lock().take()); let mut spatial_zone = spatial.zone.lock(); if let Some(spatial_zone) = spatial_zone.upgrade() { - let Some(node) = spatial_zone.spatial.node.upgrade() else {return}; + let Some(node) = spatial_zone.spatial.node.upgrade() else { + return; + }; spatial_zone.captured.remove(spatial); - let Ok(message) = serialize(&spatial.uid) else {return}; + let Ok(message) = serialize(&spatial.uid) else { + return; + }; let _ = node.send_remote_signal("release", message); } *spatial_zone = Weak::new(); @@ -83,12 +88,17 @@ impl Zone { } fn update(node: &Node, _calling_client: Arc, _message: Message) -> Result<()> { let zone = node.zone.get().unwrap(); - let Some(field) = zone.field.upgrade() else { return Err(color_eyre::eyre::eyre!("Zone's field has been destroyed")) }; + let Some(field) = zone.field.upgrade() else { + return Err(color_eyre::eyre::eyre!("Zone's field has been destroyed")); + }; let Some((zone_client, zone_node)) = zone .spatial .node .upgrade() - .and_then(|n| n.get_client().zip(Some(n))) else { return Err(color_eyre::eyre::eyre!("No client on node?")) }; + .and_then(|n| n.get_client().zip(Some(n))) + else { + return Err(color_eyre::eyre::eyre!("No client on node?")); + }; let mut old_zoneables = zone.zoneables.lock(); for (_uid, zoneable) in old_zoneables.iter() { zoneable.destroy(); diff --git a/src/objects/input/eye_pointer.rs b/src/objects/input/eye_pointer.rs index 442203b..5627fb2 100644 --- a/src/objects/input/eye_pointer.rs +++ b/src/objects/input/eye_pointer.rs @@ -10,7 +10,7 @@ use color_eyre::eyre::Result; use glam::Mat4; use nanoid::nanoid; use serde::Serialize; -use stardust_xr::schemas::{flat::Datamap, flex::flexbuffers}; +use stardust_xr::{schemas::flex::flexbuffers, values::Datamap}; use std::sync::Arc; use stereokit::StereoKitMultiThread; @@ -48,7 +48,7 @@ impl EyePointer { let mut map = fbb.start_map(); map.push("eye", 2); map.end_map(); - *self.pointer.datamap.lock() = Datamap::new(fbb.take_buffer()).ok(); + *self.pointer.datamap.lock() = Datamap::from_raw(fbb.take_buffer()).ok(); } } } diff --git a/src/objects/input/mouse_pointer.rs b/src/objects/input/mouse_pointer.rs index 4d1d93f..248e023 100644 --- a/src/objects/input/mouse_pointer.rs +++ b/src/objects/input/mouse_pointer.rs @@ -1,5 +1,5 @@ use crate::{ - core::{client::INTERNAL_CLIENT, typed_datamap::TypedDatamap}, + core::client::INTERNAL_CLIENT, nodes::{ data::{mask_matches, Mask, PulseSender, KEYMAPS, PULSE_RECEIVER_REGISTRY}, fields::Ray, @@ -12,6 +12,7 @@ use color_eyre::eyre::Result; use glam::{vec2, vec3, Mat4, Vec2, Vec3}; use nanoid::nanoid; use serde::{Deserialize, Serialize}; +use stardust_xr::values::Datamap; use std::{convert::TryFrom, sync::Arc}; use stereokit::{ray_from_mouse, ButtonState, Key, StereoKitMultiThread}; use xkbcommon::xkb::{Context, Keymap, FORMAT_TEXT_V1}; @@ -49,8 +50,8 @@ pub struct MousePointer { node: Arc, spatial: Arc, pointer: Arc, - mouse_datamap: TypedDatamap, - keyboard_datamap: TypedDatamap, + mouse_datamap: MouseEvent, + keyboard_datamap: KeyboardEvent, keyboard_sender: Arc, } impl MousePointer { @@ -122,7 +123,7 @@ impl MousePointer { }; self.mouse_datamap.scroll_continuous = vec2(0.0, mouse.scroll_change / 120.0); self.mouse_datamap.scroll_discrete = vec2(0.0, mouse.scroll_change / 120.0); - *self.pointer.datamap.lock() = self.mouse_datamap.to_datamap().ok(); + *self.pointer.datamap.lock() = Datamap::from_typed(&self.mouse_datamap).ok(); } self.send_keyboard_input(sk); } @@ -169,8 +170,14 @@ impl MousePointer { self.keyboard_datamap.keys = keys; if !self.keyboard_datamap.keys.is_empty() { - rx.send_data(&self.node.uid, self.keyboard_datamap.serialize().unwrap()) - .unwrap(); + rx.send_data( + &self.node.uid, + Datamap::from_typed(&self.keyboard_datamap) + .unwrap() + .raw() + .clone(), + ) + .unwrap(); } } } diff --git a/src/objects/input/sk_controller.rs b/src/objects/input/sk_controller.rs index 2658861..cd3674a 100644 --- a/src/objects/input/sk_controller.rs +++ b/src/objects/input/sk_controller.rs @@ -1,5 +1,5 @@ use crate::{ - core::{client::INTERNAL_CLIENT, typed_datamap::TypedDatamap}, + core::client::INTERNAL_CLIENT, nodes::{ input::{tip::Tip, InputMethod, InputType}, spatial::Spatial, @@ -9,6 +9,7 @@ use crate::{ use color_eyre::eyre::Result; use glam::{Mat4, Vec2, Vec3}; use serde::{Deserialize, Serialize}; +use stardust_xr::values::Datamap; use std::sync::Arc; use stereokit::{ named_colors::WHITE, ButtonState, Handed, Model, RenderLayer, StereoKitDraw, @@ -27,7 +28,7 @@ pub struct SkController { input: Arc, model: Model, handed: Handed, - datamap: TypedDatamap, + datamap: ControllerDatamap, } impl SkController { pub fn new(sk: &impl StereoKitMultiThread, handed: Handed) -> Result { @@ -73,6 +74,6 @@ impl SkController { self.datamap.select = controller.trigger; self.datamap.grab = controller.grip; self.datamap.scroll = controller.stick; - *self.input.datamap.lock() = self.datamap.to_datamap().ok(); + *self.input.datamap.lock() = Datamap::from_typed(&self.datamap).ok(); } } diff --git a/src/objects/input/sk_hand.rs b/src/objects/input/sk_hand.rs index 8669830..e6f1a7c 100644 --- a/src/objects/input/sk_hand.rs +++ b/src/objects/input/sk_hand.rs @@ -1,5 +1,5 @@ use crate::{ - core::{client::INTERNAL_CLIENT, typed_datamap::TypedDatamap}, + core::client::INTERNAL_CLIENT, nodes::{ input::{hand::Hand, InputMethod, InputType}, spatial::Spatial, @@ -10,7 +10,10 @@ use color_eyre::eyre::Result; use glam::Mat4; use nanoid::nanoid; use serde::{Deserialize, Serialize}; -use stardust_xr::schemas::flat::{Hand as FlatHand, Joint}; +use stardust_xr::{ + schemas::flat::{Hand as FlatHand, Joint}, + values::Datamap, +}; use std::sync::Arc; use stereokit::{ButtonState, HandJoint, Handed, StereoKitMultiThread}; @@ -33,7 +36,7 @@ pub struct SkHand { _node: Arc, input: Arc, handed: Handed, - datamap: TypedDatamap, + datamap: HandDatamap, } impl SkHand { pub fn new(handed: Handed) -> Result { @@ -98,6 +101,6 @@ impl SkHand { } self.datamap.pinch_strength = sk_hand.pinch_activation; self.datamap.grab_strength = sk_hand.grip_activation; - *self.input.datamap.lock() = self.datamap.to_datamap().ok(); + *self.input.datamap.lock() = Datamap::from_typed(&self.datamap).ok(); } }