From d7b86cd0c47e39207be2f709bca481b03da3025c Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Mon, 15 Mar 2021 14:43:30 +0100 Subject: [PATCH] Polishing of the interpreter API after review --- sixtyfps_runtime/interpreter/api.rs | 104 +++++++++++++++++++++++----- 1 file changed, 86 insertions(+), 18 deletions(-) diff --git a/sixtyfps_runtime/interpreter/api.rs b/sixtyfps_runtime/interpreter/api.rs index 92b68e94b..12ba4730c 100644 --- a/sixtyfps_runtime/interpreter/api.rs +++ b/sixtyfps_runtime/interpreter/api.rs @@ -216,32 +216,37 @@ impl ComponentDefinition { } /// Instantiate the component - /// - /// FIXME! wasm canvas id? pub fn create(&self) -> ComponentInstance { ComponentInstance { inner: self.inner.clone().create( #[cfg(target_arch = "wasm32")] - todo!(), + "canvas", ), } } + /// Instantiate the component for wasm using the given canvas id + #[cfg(target_arch = "wasm32")] + pub fn create_with_canvas_id(&self, canvas_id: &str) -> ComponentInstance { + ComponentInstance { inner: self.inner.clone().create(canvas_id) } + } + /// List of publicly declared properties or callback. - /// FIXME: this expose `sixtyfps_compilerlib::Type` (should it perhaps return an iterator instead?) + /// + /// This is internal because it exposes the `Type` from compilerlib. + /// In the future this should probably return an iterator instead. + #[doc(hidden)] pub fn properties(&self) -> HashMap { self.inner.properties() } /// The name of this Component as written in the .60 file - pub fn id(&self) -> &str { + pub fn name(&self) -> &str { self.inner.id() } } /// This represent an instance of a dynamic component -/// FIXME: Clone? (same problem as for the generated component that can be cloned but maybe not such a good idea) -#[derive(Clone)] pub struct ComponentInstance { inner: vtable::VRc< sixtyfps_corelib::component::ComponentVTable, @@ -251,13 +256,13 @@ pub struct ComponentInstance { impl ComponentInstance { /// Return the value for a public property of this component - pub fn get_property(&self, name: &str) -> Result { + pub fn get_property(&self, name: &str) -> Result { generativity::make_guard!(guard); let comp = self.inner.unerase(guard); comp.description() .get_property(comp.borrow(), name) .map(|v| Value(v)) - .map_err(|()| NoSuchPropertyError) + .map_err(|()| GetPropertyError::NoSuchProperty) } /// Return the value for a public property of this component @@ -269,14 +274,13 @@ impl ComponentInstance { .map_err(|()| todo!("set_property don't return the right error type")) } - /// FIXME: error type. - /// FIXME: what to do if the returned value is not the right type (currently! panic in the eval) - /// FIXME: name: should it be called on_callback? - pub fn set_callback_handler( + /// Set a handler for the callback with the given name. A callback with that + /// name must be defined in the document otherwise an error will be returned. + pub fn set_callback( &self, name: &str, callback: impl Fn(&[Value]) -> Value + 'static, - ) -> Result<(), NoSuchPropertyError> { + ) -> Result<(), SetCallbackError> { generativity::make_guard!(guard); let comp = self.inner.unerase(guard); comp.description() @@ -289,7 +293,7 @@ impl ComponentInstance { callback(&args).0 }), ) - .map_err(|()| NoSuchPropertyError) + .map_err(|()| SetCallbackError::NoSuchCallback) } /// Call the given callback with the arguments @@ -327,11 +331,54 @@ impl ComponentInstance { crate::run_event_loop(); self.hide(); } + + /// Clone this `ComponentInstance`. + /// + /// A `ComponentInstance` is in fact a handle to a reference counted instance. + /// This function is semanticallt the same as the one from `Clone::clone`, but + /// Clone is not implemented because of the danger of circular reference: + /// If you want to use this instance in a callback, you should capture a weak + /// reference given by [`Self::as_weak`]. + pub fn clone_strong(&self) -> Self { + Self { inner: self.inner.clone() } + } + + /// Create a weak pointer to this component + pub fn as_weak(&self) -> WeakComponentInstance { + WeakComponentInstance { inner: vtable::VRc::downgrade(&self.inner) } + } } -/// Error returned by [`ComponentInstance::get_property`] if the component does not have that property +/// A Weak references to a dynamic SixtyFPS components. +#[derive(Clone)] +pub struct WeakComponentInstance { + inner: vtable::VWeak< + sixtyfps_corelib::component::ComponentVTable, + crate::dynamic_component::ErasedComponentBox, + >, +} + +impl WeakComponentInstance { + /// Returns a new strongly referenced component if some other instance still + /// holds a strong reference. Otherwise, returns None. + pub fn upgrade(&self) -> Option { + self.inner.upgrade().map(|inner| ComponentInstance { inner }) + } + + /// Convenience function that returns a new stronlyg referenced component if + /// some other instance still holds a strong reference. Otherwise, this function + /// panics. + pub fn unwrap(&self) -> ComponentInstance { + self.upgrade().unwrap() + } +} + +/// Error returned by [`ComponentInstance::get_property`] #[derive(Debug)] -pub struct NoSuchPropertyError; +pub enum GetPropertyError { + /// There is no property with the given name + NoSuchProperty, +} /// Error returned by [`ComponentInstance::set_property`] #[derive(Debug)] @@ -342,9 +389,17 @@ pub enum SetPropertyError { WrongType, } +/// Error returned by [`ComponentInstance::set_callback`] +#[derive(Debug)] +pub enum SetCallbackError { + /// There is no callback with the given name + NoSuchCallback, +} + /// Error returned by [`ComponentInstance::call_callback`] pub enum CallCallbackError { - //TODO + /// There is no callback with the given name + NoSuchCallback, } /// The structure for configuring aspects of the compilation of `.60` markup files to Rust. @@ -376,4 +431,17 @@ impl CompilerConfiguration { config.style = Some(style); Self { config } } + + /// Create a new configuration that will use the provided callback for loading. + pub fn with_file_loader( + _file_loader_fallback: Box< + dyn Fn( + &Path, + ) -> core::pin::Pin< + Box>>, + >, + >, + ) -> Self { + todo!(); + } }