From 5b44cc54d90189c8ec01b60a6add483d3355ef8c Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Wed, 9 Nov 2022 14:56:56 +0100 Subject: [PATCH] Don't generate a native setter for `out property` --- internal/compiler/generator/cpp.rs | 36 ++++++++++--------- internal/compiler/generator/rust.rs | 36 ++++++++++--------- internal/compiler/llr/item_tree.rs | 9 ++++- internal/compiler/llr/lower_to_item_tree.rs | 9 +++-- .../llr/optim_passes/count_property_use.rs | 8 ++--- internal/compiler/object_tree.rs | 2 ++ internal/compiler/passes/check_public_api.rs | 10 ++++-- 7 files changed, 66 insertions(+), 44 deletions(-) diff --git a/internal/compiler/generator/cpp.rs b/internal/compiler/generator/cpp.rs index 34be56efc..cfc4237a6 100644 --- a/internal/compiler/generator/cpp.rs +++ b/internal/compiler/generator/cpp.rs @@ -1779,12 +1779,12 @@ fn generate_public_api_for_properties( ctx: &EvaluationContext, ) -> Vec { let mut declarations = Vec::new(); - for (p, (ty, r)) in public_properties.iter() { - let prop_ident = ident(p); + for p in public_properties.iter() { + let prop_ident = ident(&p.name); - let access = access_member(r, ctx); + let access = access_member(&p.prop, ctx); - if let Type::Callback { args, return_type } = ty { + if let Type::Callback { args, return_type } = &p.ty { let param_types = args.iter().map(|t| t.cpp_type().unwrap()).collect::>(); let return_type = return_type.as_ref().map_or("void".into(), |t| t.cpp_type().unwrap()); let callback_emitter = vec![ @@ -1796,7 +1796,7 @@ fn generate_public_api_for_properties( ), ]; declarations.push(Declaration::Function(Function { - name: format!("invoke_{}", ident(p)), + name: format!("invoke_{}", ident(&p.name)), signature: format!( "({}) const -> {}", param_types @@ -1810,7 +1810,7 @@ fn generate_public_api_for_properties( ..Default::default() })); declarations.push(Declaration::Function(Function { - name: format!("on_{}", ident(p)), + name: format!("on_{}", ident(&p.name)), template_parameters: Some("typename Functor".into()), signature: "(Functor && callback_handler) const".into(), statements: Some(vec![ @@ -1820,7 +1820,7 @@ fn generate_public_api_for_properties( ..Default::default() })); } else { - let cpp_property_type = ty.cpp_type().expect("Invalid type in public properties"); + let cpp_property_type = p.ty.cpp_type().expect("Invalid type in public properties"); let prop_getter: Vec = vec![ "[[maybe_unused]] auto self = this;".into(), format!("return {}.get();", access), @@ -1832,16 +1832,18 @@ fn generate_public_api_for_properties( ..Default::default() })); - let prop_setter: Vec = vec![ - "[[maybe_unused]] auto self = this;".into(), - property_set_value_code(r, "value", ctx) + ";", - ]; - declarations.push(Declaration::Function(Function { - name: format!("set_{}", &prop_ident), - signature: format!("(const {} &value) const", &cpp_property_type), - statements: Some(prop_setter), - ..Default::default() - })); + if !p.read_only { + let prop_setter: Vec = vec![ + "[[maybe_unused]] auto self = this;".into(), + property_set_value_code(&p.prop, "value", ctx) + ";", + ]; + declarations.push(Declaration::Function(Function { + name: format!("set_{}", &prop_ident), + signature: format!("(const {} &value) const", &cpp_property_type), + statements: Some(prop_setter), + ..Default::default() + })); + } } } declarations diff --git a/internal/compiler/generator/rust.rs b/internal/compiler/generator/rust.rs index 79256698f..bc76bf851 100644 --- a/internal/compiler/generator/rust.rs +++ b/internal/compiler/generator/rust.rs @@ -524,11 +524,11 @@ fn public_api( ctx: &EvaluationContext, ) -> TokenStream { let mut property_and_callback_accessors: Vec = vec![]; - for (p, (ty, r)) in public_properties { - let prop_ident = ident(p); - let prop = access_member(r, ctx); + for p in public_properties { + let prop_ident = ident(&p.name); + let prop = access_member(&p.prop, ctx); - if let Type::Callback { args, return_type } = ty { + if let Type::Callback { args, return_type } = &p.ty { let callback_args = args.iter().map(|a| rust_primitive_type(a).unwrap()).collect::>(); let return_type = @@ -556,12 +556,11 @@ fn public_api( } )); } else { - let rust_property_type = rust_primitive_type(ty).unwrap(); + let rust_property_type = rust_primitive_type(&p.ty).unwrap(); let getter_ident = format_ident!("get_{}", prop_ident); - let setter_ident = format_ident!("set_{}", prop_ident); - let prop_expression = primitive_property_value(ty, prop); + let prop_expression = primitive_property_value(&p.ty, prop); property_and_callback_accessors.push(quote!( #[allow(dead_code)] @@ -573,16 +572,19 @@ fn public_api( } )); - let set_value = property_set_value_tokens(r, quote!(value), ctx); - property_and_callback_accessors.push(quote!( - #[allow(dead_code)] - pub fn #setter_ident(&self, value: #rust_property_type) { - #[allow(unused_imports)] - use slint::private_unstable_api::re_exports::*; - let _self = #self_init; - #set_value - } - )); + if !p.read_only { + let setter_ident = format_ident!("set_{}", prop_ident); + let set_value = property_set_value_tokens(&p.prop, quote!(value), ctx); + property_and_callback_accessors.push(quote!( + #[allow(dead_code)] + pub fn #setter_ident(&self, value: #rust_property_type) { + #[allow(unused_imports)] + use slint::private_unstable_api::re_exports::*; + let _self = #self_init; + #set_value + } + )); + } } } diff --git a/internal/compiler/llr/item_tree.rs b/internal/compiler/llr/item_tree.rs index 796dc3509..6aec938ff 100644 --- a/internal/compiler/llr/item_tree.rs +++ b/internal/compiler/llr/item_tree.rs @@ -352,4 +352,11 @@ impl PublicComponent { } } -pub type PublicProperties = BTreeMap; +#[derive(Debug, Clone)] +pub struct PublicProperty { + pub name: String, + pub ty: Type, + pub prop: PropertyReference, + pub read_only: bool, +} +pub type PublicProperties = Vec; diff --git a/internal/compiler/llr/lower_to_item_tree.rs b/internal/compiler/llr/lower_to_item_tree.rs index 24c25a949..c32872f58 100644 --- a/internal/compiler/llr/lower_to_item_tree.rs +++ b/internal/compiler/llr/lower_to_item_tree.rs @@ -7,7 +7,7 @@ use crate::expression_tree::Expression as tree_Expression; use crate::langtype::{ElementType, Type}; use crate::llr::item_tree::*; use crate::namedreference::NamedReference; -use crate::object_tree::{Component, ElementRc}; +use crate::object_tree::{Component, ElementRc, PropertyVisibility}; use std::collections::HashMap; use std::rc::Rc; @@ -661,7 +661,12 @@ fn public_properties( .map(|(p, c)| { let property_reference = mapping .map_property_reference(&NamedReference::new(&component.root_element, p), state); - (p.clone(), (c.property_type.clone(), property_reference)) + PublicProperty { + name: p.clone(), + ty: c.property_type.clone(), + prop: property_reference, + read_only: c.visibility == PropertyVisibility::Output, + } }) .collect() } diff --git a/internal/compiler/llr/optim_passes/count_property_use.rs b/internal/compiler/llr/optim_passes/count_property_use.rs index f0edf5547..8ec58c698 100644 --- a/internal/compiler/llr/optim_passes/count_property_use.rs +++ b/internal/compiler/llr/optim_passes/count_property_use.rs @@ -11,13 +11,13 @@ pub fn count_property_use(root: &PublicComponent) { // Visit the root properties that are used. // 1. the public properties let root_ctx = EvaluationContext::new_sub_component(root, &root.item_tree.root, (), None); - for (_, pr) in root.public_properties.values() { - visit_property(pr, &root_ctx); + for p in root.public_properties.iter() { + visit_property(&p.prop, &root_ctx); } for g in root.globals.iter().filter(|g| g.exported) { let ctx = EvaluationContext::new_global(root, g, ()); - for (_, pr) in g.public_properties.values() { - visit_property(pr, &ctx); + for p in g.public_properties.iter() { + visit_property(&p.prop, &ctx); } } diff --git a/internal/compiler/object_tree.rs b/internal/compiler/object_tree.rs index 4d429aa89..1a354fe0b 100644 --- a/internal/compiler/object_tree.rs +++ b/internal/compiler/object_tree.rs @@ -833,6 +833,7 @@ impl Element { PropertyDeclaration { property_type: Type::InferredCallback, node: Some(Either::Right(sig_decl)), + visibility: PropertyVisibility::InOut, ..Default::default() }, ); @@ -848,6 +849,7 @@ impl Element { PropertyDeclaration { property_type: Type::Callback { return_type, args }, node: Some(Either::Right(sig_decl)), + visibility: PropertyVisibility::InOut, ..Default::default() }, ); diff --git a/internal/compiler/passes/check_public_api.rs b/internal/compiler/passes/check_public_api.rs index c29a4b3cd..f96e0c726 100644 --- a/internal/compiler/passes/check_public_api.rs +++ b/internal/compiler/passes/check_public_api.rs @@ -6,7 +6,7 @@ use std::rc::Rc; use crate::diagnostics::{BuildDiagnostics, DiagnosticLevel}; -use crate::object_tree::{Component, Document}; +use crate::object_tree::{Component, Document, PropertyVisibility}; pub fn check_public_api(doc: &Document, diag: &mut BuildDiagnostics) { check_public_api_component(&doc.root_component, diag); @@ -27,8 +27,12 @@ fn check_public_api_component(root_component: &Rc, diag: &mut BuildDi let mut pa = root_elem.property_analysis.borrow_mut(); root_elem.property_declarations.iter_mut().for_each(|(n, d)| { if d.property_type.ok_for_public_api() { - d.expose_in_public_api = true; - pa.entry(n.to_string()).or_default().is_set = true; + if d.visibility != PropertyVisibility::Private { + d.expose_in_public_api = true; + if d.visibility != PropertyVisibility::Output { + pa.entry(n.to_string()).or_default().is_set = true; + } + } } else { diag.push_diagnostic( format!("Properties of type {} are not supported yet for public API. The property will not be exposed", d.property_type),