diff --git a/rust/client/build.rs b/rust/client/build.rs index 3edeb9d..c6ea8e2 100644 --- a/rust/client/build.rs +++ b/rust/client/build.rs @@ -114,7 +114,7 @@ fn main() -> anyhow::Result<()> { output.push_str("\n"); - output.push_str("fn append_component_widget_child(parent: &ComponentWidgetWrapper, child: ComponentWidgetWrapper) {\n"); + output.push_str("fn append_component_widget_child(parent: &ComponentWidgetWrapper, child: ComponentWidgetWrapper) -> anyhow::Result<()> {\n"); output.push_str(" let mut parent = parent.get_mut();\n"); output.push_str(" match *parent {\n"); output.push_str(" ComponentWidget::TextPart { .. } => panic!(\"text part cannot be a parent\"),\n"); @@ -126,16 +126,33 @@ fn main() -> anyhow::Result<()> { if has_children { output.push_str(&format!(" ComponentWidget::{} {{ ref mut children, .. }} => {{\n", name)); + output.push_str(" match get_component_widget_type_internal(&child) {\n"); + + match component.children() { + Children::Members { members } => { + for member in members { + output.push_str(&format!(" (\"gauntlet:{}\", _) => (),\n", member.component_internal_name())); + } + } + Children::String => { + output.push_str(&format!(" (\"gauntlet:___text_part___\", _) => (),\n")); + } + Children::None => {} + } + + output.push_str(&format!(" (_, name) => Err(anyhow::anyhow!(\"{} cannot have {{}} child\", name))?\n", name)); + output.push_str(" };\n"); output.push_str(" children.push(child)\n"); output.push_str(" }\n"); } else { output.push_str(&format!(" ComponentWidget::{} {{ .. }} => {{\n", name)); - output.push_str(&format!(" panic!(\"{} cannot be a parent\")\n", internal_name)); + output.push_str(&format!(" Err(anyhow::anyhow!(\"{} cannot have children\"))?\n", name)); output.push_str(" }\n"); } } - output.push_str(" }\n"); + output.push_str(" };\n"); + output.push_str(" Ok(())\n"); output.push_str("}\n"); output.push_str("\n"); @@ -158,7 +175,7 @@ fn main() -> anyhow::Result<()> { output.push_str("\n"); - output.push_str("fn get_component_widget_children(widget: &ComponentWidgetWrapper) -> Vec {\n"); + output.push_str("fn get_component_widget_children(widget: &ComponentWidgetWrapper) -> anyhow::Result> {\n"); output.push_str(" let widget = widget.get();\n"); output.push_str(" let children = match *widget {\n"); output.push_str(" ComponentWidget::TextPart { .. } => panic!(\"text part cannot have children\"),\n"); @@ -174,18 +191,18 @@ fn main() -> anyhow::Result<()> { output.push_str(" }\n"); } else { output.push_str(&format!(" ComponentWidget::{} {{ .. }} => {{\n", name)); - output.push_str(&format!(" panic!(\"{} cannot have children\")\n", internal_name)); + output.push_str(&format!(" Err(anyhow::anyhow!(\"{} cannot have children\"))?\n", name)); output.push_str(" }\n"); } } output.push_str(" };\n"); - output.push_str(" children.iter().cloned().collect()\n"); + output.push_str(" Ok(children.iter().cloned().collect())\n"); output.push_str("}\n"); output.push_str("\n"); - output.push_str("fn set_component_widget_children(widget: &ComponentWidgetWrapper, new_children: Vec) {\n"); + output.push_str("fn set_component_widget_children(widget: &ComponentWidgetWrapper, new_children: Vec) -> anyhow::Result<()> {\n"); output.push_str(" let mut widget = widget.get_mut();\n"); output.push_str(" match *widget {\n"); output.push_str(" ComponentWidget::TextPart { .. } => panic!(\"text part cannot have children\"),\n"); @@ -197,16 +214,35 @@ fn main() -> anyhow::Result<()> { if has_children { output.push_str(&format!(" ComponentWidget::{} {{ ref mut children, .. }} => {{\n", name)); + output.push_str(" for new_child in &new_children {\n"); + output.push_str(" match get_component_widget_type_internal(new_child) {\n"); + + match component.children() { + Children::Members { members } => { + for member in members { + output.push_str(&format!(" (\"gauntlet:{}\", _) => (),\n", member.component_internal_name())); + } + } + Children::String => { + output.push_str(&format!(" (\"gauntlet:___text_part___\", _) => (),\n")); + } + Children::None => {} + } + + output.push_str(&format!(" (_, name) => Err(anyhow::anyhow!(\"{} cannot have {{}} child\", name))?\n", name)); + output.push_str(" };\n"); + output.push_str(" }\n"); output.push_str(" *children = new_children\n"); output.push_str(" }\n"); } else { output.push_str(&format!(" ComponentWidget::{} {{ .. }} => {{\n", name)); - output.push_str(&format!(" panic!(\"{} cannot have children\")\n", internal_name)); + output.push_str(&format!(" Err(anyhow::anyhow!(\"{} cannot have children\"))?\n", internal_name)); output.push_str(" }\n"); } } - output.push_str(" }\n"); + output.push_str(" };\n"); + output.push_str(" Ok(())\n"); output.push_str("}\n"); output.push_str("\n"); @@ -228,6 +264,23 @@ fn main() -> anyhow::Result<()> { output.push_str("\n"); + output.push_str("fn get_component_widget_type_internal(widget: &ComponentWidgetWrapper) -> (&str, &str) {\n"); + output.push_str(" let widget = widget.get();\n"); + output.push_str(" match *widget {\n"); + output.push_str(" ComponentWidget::TextPart { .. } => (\"gauntlet:___text_part___\", \"TextPart\"),\n"); + + for component in &components { + let name = component.name(); + let internal_name = component.internal_name(); + + output.push_str(&format!(" ComponentWidget::{} {{ .. }} => (\"gauntlet:{}\", \"{}\"),\n", name, internal_name, name)); + } + + output.push_str(" }\n"); + output.push_str("}\n"); + output.push_str("\n"); + + output.push_str("fn parse_optional_string(properties: &HashMap, name: &str) -> anyhow::Result> {\n"); output.push_str(" match properties.get(name) {\n"); output.push_str(" None => Ok(None),\n"); diff --git a/rust/client/src/dbus.rs b/rust/client/src/dbus.rs index b08a2a4..36bc52d 100644 --- a/rust/client/src/dbus.rs +++ b/rust/client/src/dbus.rs @@ -49,9 +49,14 @@ impl DbusClient { Ok(widget) } - fn append_child(&mut self, plugin_id: &str, parent: DBusUiWidget, child: DBusUiWidget) -> Result<()> { + async fn append_child(&mut self, plugin_id: &str, parent: DBusUiWidget, child: DBusUiWidget) -> Result<()> { let data = NativeUiRequestData::AppendChild { parent: parent.into(), child: child.into() }; - self.context_tx.send((PluginId::from_string(plugin_id), data)); + let input = (PluginId::from_string(plugin_id), data); + + match self.context_tx.send_receive(input).await { + NativeUiResponseData::AppendChild { result } => result?, + value @ _ => panic!("unsupported response type {:?}", value), + }; Ok(()) } @@ -73,10 +78,15 @@ impl DbusClient { Ok(widget) } - fn replace_container_children(&self, plugin_id: &str, container: DBusUiWidget, new_children: Vec) -> Result<()> { + async fn replace_container_children(&self, plugin_id: &str, container: DBusUiWidget, new_children: Vec) -> Result<()> { let new_children = new_children.into_iter().map(|child| child.into()).collect(); let data = NativeUiRequestData::ReplaceContainerChildren { container: container.into(), new_children }; - self.context_tx.send((PluginId::from_string(plugin_id), data)); + let data = (PluginId::from_string(plugin_id), data); + + match self.context_tx.send_receive(data).await { + NativeUiResponseData::ReplaceContainerChildren { result } => result?, + value @ _ => panic!("unsupported response type {:?}", value), + }; Ok(()) } diff --git a/rust/client/src/model.rs b/rust/client/src/model.rs index a84b086..0a624b6 100644 --- a/rust/client/src/model.rs +++ b/rust/client/src/model.rs @@ -28,6 +28,12 @@ pub enum NativeUiResponseData { CloneInstance { widget: anyhow::Result }, + AppendChild { + result: anyhow::Result<()> + }, + ReplaceContainerChildren { + result: anyhow::Result<()> + }, } #[derive(Debug)] diff --git a/rust/client/src/ui/mod.rs b/rust/client/src/ui/mod.rs index 2c1f1b6..a2b85bf 100644 --- a/rust/client/src/ui/mod.rs +++ b/rust/client/src/ui/mod.rs @@ -325,7 +325,11 @@ async fn request_loop( responder.respond(response) } NativeUiRequestData::AppendChild { parent, child } => { - client_context.append_child(&plugin_id, parent, child); + let result = client_context.append_child(&plugin_id, parent, child); + + let response = NativeUiResponseData::AppendChild { result }; + + responder.respond(response) } NativeUiRequestData::CloneInstance { widget, @@ -340,7 +344,11 @@ async fn request_loop( responder.respond(response) } NativeUiRequestData::ReplaceContainerChildren { container, new_children } => { - client_context.replace_container_children(&plugin_id, container, new_children); + let result = client_context.replace_container_children(&plugin_id, container, new_children); + + let response = NativeUiResponseData::AppendChild { result }; + + responder.respond(response) } } } diff --git a/rust/client/src/ui/plugin_container.rs b/rust/client/src/ui/plugin_container.rs index 4ffe5ca..70231cd 100644 --- a/rust/client/src/ui/plugin_container.rs +++ b/rust/client/src/ui/plugin_container.rs @@ -65,7 +65,7 @@ impl PluginViewContainer { NativeUiWidget { widget_id: self.root_id, - widget_type: "___root___".to_owned() + widget_type: "gauntlet:___root___".to_owned() } } @@ -78,7 +78,7 @@ impl PluginViewContainer { fn create_text_instance(&mut self, text: &str) -> anyhow::Result { tracing::trace!("create_text_instance is called. text: {:?}", text); - let widget = self.create_native_widget("text", |id| ComponentWidgetWrapper::text_part(id, text)); + let widget = self.create_native_widget("gauntlet:___text_part___", |id| ComponentWidgetWrapper::text_part(id, text)); tracing::trace!("create_text_instance is returned. widget: {:?}", widget); widget } @@ -92,9 +92,7 @@ impl PluginViewContainer { if keep_children { let new_widget_builtin = self.get_builtin_widget(new_widget.clone()); - if new_widget_builtin.can_have_children() { - new_widget_builtin.set_children(widget.get_children()); - } + new_widget_builtin.set_children(widget.get_children()?)?; } tracing::trace!("clone_instance is returned. widget: {:?}", widget); @@ -102,15 +100,15 @@ impl PluginViewContainer { Ok(new_widget) } - fn append_child(&mut self, parent: NativeUiWidget, child: NativeUiWidget) { + fn append_child(&mut self, parent: NativeUiWidget, child: NativeUiWidget) -> anyhow::Result<()> { tracing::trace!("append_child is called. parent: {:?}, child: {:?}", parent, child); let parent = self.get_builtin_widget(parent); let child = self.get_builtin_widget(child); - parent.append_child(child); + parent.append_child(child) } - fn replace_container_children(&mut self, container: NativeUiWidget, new_children: Vec) { + fn replace_container_children(&mut self, container: NativeUiWidget, new_children: Vec) -> anyhow::Result<()> { tracing::trace!("replace_container_children is called. container: {:?}, new_children: {:?}", container, new_children); let container = self.get_builtin_widget(container); @@ -118,7 +116,7 @@ impl PluginViewContainer { .map(|child| self.get_builtin_widget(child)) .collect(); - container.set_children(children); + container.set_children(children) } } @@ -180,7 +178,7 @@ impl ClientContext { self.get_view_container_mut(plugin_id).create_text_instance(text) } - pub fn append_child(&mut self, plugin_id: &PluginId, parent: NativeUiWidget, child: NativeUiWidget) { + pub fn append_child(&mut self, plugin_id: &PluginId, parent: NativeUiWidget, child: NativeUiWidget) -> anyhow::Result<()> { self.get_view_container_mut(plugin_id).append_child(parent, child) } @@ -188,7 +186,7 @@ impl ClientContext { self.get_view_container_mut(plugin_id).clone_instance(widget, widget_type, new_props, keep_children) } - pub fn replace_container_children(&mut self, plugin_id: &PluginId, container: NativeUiWidget, new_children: Vec) { + pub fn replace_container_children(&mut self, plugin_id: &PluginId, container: NativeUiWidget, new_children: Vec) -> anyhow::Result<()> { self.get_view_container_mut(plugin_id).replace_container_children(container, new_children) } } \ No newline at end of file diff --git a/rust/client/src/ui/widget.rs b/rust/client/src/ui/widget.rs index a8e8dd3..06026d0 100644 --- a/rust/client/src/ui/widget.rs +++ b/rust/client/src/ui/widget.rs @@ -137,19 +137,15 @@ impl ComponentWidgetWrapper { } } - pub fn append_child(&self, child: ComponentWidgetWrapper) { - append_component_widget_child(&self, child); + pub fn append_child(&self, child: ComponentWidgetWrapper) -> anyhow::Result<()> { + append_component_widget_child(&self, child) } - pub fn can_have_children(&self) -> bool { - can_component_widget_have_children(&self) - } - - pub fn get_children(&self) -> Vec { + pub fn get_children(&self) -> anyhow::Result> { get_component_widget_children(&self) } - pub fn set_children(&self, new_children: Vec) { + pub fn set_children(&self, new_children: Vec) -> anyhow::Result<()> { set_component_widget_children(&self, new_children) } diff --git a/rust/component_model/src/lib.rs b/rust/component_model/src/lib.rs index 4fbba39..1c54bff 100644 --- a/rust/component_model/src/lib.rs +++ b/rust/component_model/src/lib.rs @@ -111,10 +111,24 @@ pub enum Children { pub struct ChildrenMember { #[serde(rename = "memberName")] member_name: String, + #[serde(rename = "componentInternalName")] + component_internal_name: String, #[serde(rename = "componentName")] component_name: ComponentName, } +impl ChildrenMember { + pub fn member_name(&self) -> &str { + &self.member_name + } + pub fn component_internal_name(&self) -> &str { + &self.component_internal_name + } + pub fn component_name(&self) -> &ComponentName { + &self.component_name + } +} + fn children_members(members: Vec) -> Children { Children::Members { @@ -133,6 +147,7 @@ fn children_none() -> Children { fn member(member_name: impl ToString, component: &Component) -> ChildrenMember { ChildrenMember { member_name: member_name.to_string(), + component_internal_name: component.internal_name.clone(), component_name: component.name.clone() } }