diff --git a/api/cpp/include/slint.h b/api/cpp/include/slint.h index dd609d3ea..d6cdfe9f3 100644 --- a/api/cpp/include/slint.h +++ b/api/cpp/include/slint.h @@ -42,10 +42,12 @@ namespace slint { namespace private_api { using cbindgen_private::ComponentVTable; using cbindgen_private::ItemVTable; +using ComponentRc = vtable::VRc; using ComponentRef = vtable::VRef; +using IndexRange = cbindgen_private::IndexRange; using ItemRef = vtable::VRef; using ItemVisitorRefMut = vtable::VRefMut; -using cbindgen_private::ComponentRc; +using cbindgen_private::ComponentWeak; using cbindgen_private::ItemWeak; using cbindgen_private::TraversalOrder; } @@ -846,6 +848,16 @@ public: return { &C::static_vtable, const_cast(&(**x.ptr)) }; } + void component_at(int i, vtable::VWeak *result) const + { + const auto &x = inner->data.at(i); + *result = vtable::VWeak{x.ptr->into_dyn()}; + } + + private_api::IndexRange index_range() const { + return private_api::IndexRange { 0, inner->data.size() }; + } + float compute_layout_listview(const private_api::Property *viewport_width, float listview_width) const { diff --git a/api/rs/slint/lib.rs b/api/rs/slint/lib.rs index 483040914..18c5f69b9 100644 --- a/api/rs/slint/lib.rs +++ b/api/rs/slint/lib.rs @@ -1,6 +1,8 @@ // Copyright © SixtyFPS GmbH // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial +// cSpell: ignore buildrs + /*! # Slint @@ -283,7 +285,7 @@ pub mod re_exports { pub use i_slint_core::callbacks::Callback; pub use i_slint_core::component::{ free_component_item_graphics_resources, init_component_items, Component, ComponentRefPin, - ComponentVTable, + ComponentVTable, ComponentWeak, IndexRange, }; pub use i_slint_core::graphics::*; pub use i_slint_core::input::{ diff --git a/internal/compiler/generator/cpp.rs b/internal/compiler/generator/cpp.rs index 5ce3f5c0c..0f8a97c14 100644 --- a/internal/compiler/generator/cpp.rs +++ b/internal/compiler/generator/cpp.rs @@ -848,15 +848,25 @@ fn generate_item_tree( let mut visit_children_statements = vec![ "static const auto dyn_visit = [] (const uint8_t *base, [[maybe_unused]] slint::private_api::TraversalOrder order, [[maybe_unused]] slint::private_api::ItemVisitorRefMut visitor, [[maybe_unused]] uintptr_t dyn_index) -> uint64_t {".to_owned(), format!(" [[maybe_unused]] auto self = reinterpret_cast(base);", item_tree_class_name)]; + let mut subtree_range_statement = vec![" std::abort();".into()]; + let mut subtree_component_statement = vec![" std::abort();".into()]; if target_struct.members.iter().any(|(_, declaration)| { matches!(&declaration, Declaration::Function(func @ Function { .. }) if func.name == "visit_dynamic_children") }) { visit_children_statements .push(" return self->visit_dynamic_children(dyn_index, order, visitor);".into()); + subtree_range_statement = vec![ + format!("auto self = reinterpret_cast(component.instance);", item_tree_class_name), + "return self->subtree_range(dyn_index);".to_owned(), + ]; + subtree_component_statement = vec![ + format!("auto self = reinterpret_cast(component.instance);", item_tree_class_name), + "self->subtree_component(dyn_index, subtree_index, result);".to_owned(), + ]; } else { visit_children_statements.push(" std::abort();".into()); - } + } visit_children_statements.extend([ "};".into(), @@ -888,6 +898,28 @@ fn generate_item_tree( }), )); + target_struct.members.push(( + Access::Private, + Declaration::Function(Function { + name: "get_subtree_range".into(), + signature: "([[maybe_unused]] slint::private_api::ComponentRef component, [[maybe_unused]] uintptr_t dyn_index) -> slint::private_api::IndexRange".into(), + is_static: true, + statements: Some(subtree_range_statement), + ..Default::default() + }), + )); + + target_struct.members.push(( + Access::Private, + Declaration::Function(Function { + name: "get_subtree_component".into(), + signature: "([[maybe_unused]] slint::private_api::ComponentRef component, [[maybe_unused]] uintptr_t dyn_index, [[maybe_unused]] uintptr_t subtree_index, [[maybe_unused]] slint::private_api::ComponentWeak *result) -> void".into(), + is_static: true, + statements: Some(subtree_component_statement), + ..Default::default() + }), + )); + target_struct.members.push(( Access::Private, Declaration::Function(Function { @@ -910,7 +942,7 @@ fn generate_item_tree( format!( // that does not work when the parent is not a component with a ComponentVTable //" *result = slint::private_api::parent_item(self->parent->self_weak.into_dyn(), self->parent->get_item_tree(), {});", - "self->parent->self_weak.vtable()->parent_item(self->parent->self_weak.lock()->borrow(), {}, result);", + "*result = {{ self->parent->self_weak, {} }};", parent_index, ) } else { @@ -934,6 +966,17 @@ fn generate_item_tree( }), )); + target_struct.members.push(( + Access::Private, + Declaration::Function(Function { + name: "subtree_index".into(), + signature: "(slint::private_api::ComponentRef /* component */) -> uintptr_t".into(), + is_static: true, + statements: Some(vec!["/* unimplemented! */".to_owned(), "return 0;".into()]), + ..Default::default() + }), + )); + target_struct.members.push(( Access::Private, Declaration::Function(Function { @@ -995,7 +1038,7 @@ fn generate_item_tree( ty: "const slint::private_api::ComponentVTable".to_owned(), name: format!("{}::static_vtable", item_tree_class_name), init: Some(format!( - "{{ visit_children, get_item_ref, get_item_tree, parent_item, layout_info, slint::private_api::drop_in_place<{}>, slint::private_api::dealloc }}", + "{{ visit_children, get_item_ref, get_subtree_range, get_subtree_component, get_item_tree, parent_item, subtree_index, layout_info, slint::private_api::drop_in_place<{}>, slint::private_api::dealloc }}", item_tree_class_name) ), ..Default::default() @@ -1181,6 +1224,8 @@ fn generate_sub_component( } let mut children_visitor_cases = Vec::new(); + let mut subtrees_ranges_cases = Vec::new(); + let mut subtrees_components_cases = Vec::new(); let mut subcomponent_init_code = Vec::new(); for sub in &component.sub_components { @@ -1223,6 +1268,23 @@ fn generate_sub_component( id = field_name, base = repeater_offset, )); + subtrees_ranges_cases.push(format!( + "\n {case_code} {{ + return self->{id}.subtree_range(dyn_index - {base}); + }}", + case_code = case_code, + id = field_name, + base = repeater_offset, + )); + subtrees_components_cases.push(format!( + "\n {case_code} {{ + self->{id}.subtree_component(dyn_index - {base}, subtree_index, result); + return; + }}", + case_code = case_code, + id = field_name, + base = repeater_offset, + )); } target_struct.members.push(( @@ -1321,6 +1383,25 @@ fn generate_sub_component( i = idx, e_u = ensure_updated, )); + subtrees_ranges_cases.push(format!( + "\n case {i}: {{ + {e_u} + return self->{id}.index_range(); + }}", + i = idx, + e_u = ensure_updated, + id = repeater_id, + )); + subtrees_components_cases.push(format!( + "\n case {i}: {{ + {e_u} + self->{id}.component_at(subtree_index, result); + return; + }}", + i = idx, + e_u = ensure_updated, + id = repeater_id, + )); target_struct.members.push(( Access::Private, @@ -1382,6 +1463,32 @@ fn generate_sub_component( ..Default::default() }), )); + target_struct.members.push(( + field_access, + Declaration::Function(Function { + name: "subtree_range".into(), + signature: "(uintptr_t dyn_index) const -> slint::private_api::IndexRange".into(), + statements: Some(vec![ + "[[maybe_unused]] auto self = this;".to_owned(), + format!(" switch(dyn_index) {{ {} }};", subtrees_ranges_cases.join("")), + " std::abort();".to_owned(), + ]), + ..Default::default() + }), + )); + target_struct.members.push(( + field_access, + Declaration::Function(Function { + name: "subtree_component".into(), + signature: "(uintptr_t dyn_index, [[maybe_unused]] uintptr_t subtree_index, [[maybe_unused]] slint::private_api::ComponentWeak *result) const -> void".into(), + statements: Some(vec![ + "[[maybe_unused]] auto self = this;".to_owned(), + format!(" switch(dyn_index) {{ {} }};", subtrees_components_cases.join("")), + " std::abort();".to_owned(), + ]), + ..Default::default() + }), + )); } } diff --git a/internal/compiler/generator/rust.rs b/internal/compiler/generator/rust.rs index 579dc2516..ee9169a29 100644 --- a/internal/compiler/generator/rust.rs +++ b/internal/compiler/generator/rust.rs @@ -1,6 +1,8 @@ // Copyright © SixtyFPS GmbH // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial +// cSpell: ignore conv powf punct + /*! module for the Rust code generator Some convention used in the generated code: @@ -117,7 +119,7 @@ pub fn generate(doc: &Document) -> TokenStream { let sub_compos = llr .sub_components .iter() - .map(|sub_compo| generate_sub_component(sub_compo, &llr, None, quote!())) + .map(|sub_compo| generate_sub_component(sub_compo, &llr, None, quote!(), None)) .collect::>(); let compo = generate_public_component(&llr); @@ -243,7 +245,7 @@ fn generate_public_component(llr: &llr::PublicComponent) -> TokenStream { let global_container_id = format_ident!("Globals_{}", public_component_id); let component = - generate_item_tree(&llr.item_tree, llr, None, quote!(globals: #global_container_id)); + generate_item_tree(&llr.item_tree, llr, None, quote!(globals: #global_container_id), None); let ctx = EvaluationContext { public_component: llr, @@ -515,6 +517,7 @@ fn generate_sub_component( root: &llr::PublicComponent, parent_ctx: Option, extra_fields: TokenStream, + index_property: Option, ) -> TokenStream { let inner_component_id = inner_component_id(component); @@ -527,7 +530,9 @@ fn generate_sub_component( let mut extra_components = component .popup_windows .iter() - .map(|c| generate_item_tree(c, root, Some(ParentCtx::new(&ctx, None)), quote!())) + .map(|c| { + generate_item_tree(c, root, Some(ParentCtx::new(&ctx, None)), quote!(), index_property) + }) .collect::>(); let mut declared_property_vars = vec![]; @@ -592,6 +597,8 @@ fn generate_sub_component( let mut repeated_element_names: Vec = vec![]; let mut repeated_visit_branch: Vec = vec![]; let mut repeated_element_components: Vec = vec![]; + let mut repeated_subtree_ranges: Vec = vec![]; + let mut repeated_subtree_components: Vec = vec![]; for (idx, repeated) in component.repeated.iter().enumerate() { extra_components.push(generate_repeated_component( @@ -643,6 +650,19 @@ fn generate_sub_component( _self.#repeater_id.visit(order, visitor) } )); + repeated_subtree_ranges.push(quote!( + #idx => { + #ensure_updated + let (start, end) = _self.#repeater_id.range(); + slint::re_exports::IndexRange { start, end } + } + )); + repeated_subtree_components.push(quote!( + #idx => { + #ensure_updated + *result = vtable::VRc::downgrade(&vtable::VRc::into_dyn(_self.#repeater_id.component_at(subtree_index).unwrap())) + } + )); repeated_element_names.push(repeater_id); repeated_element_components.push(rep_inner_component_id); } @@ -687,6 +707,16 @@ fn generate_sub_component( #sub_compo_field.apply_pin(_self).visit_dynamic_children(dyn_index - #repeater_offset, order, visitor) } )); + repeated_subtree_ranges.push(quote!( + #repeater_offset..=#last_repeater => { + #sub_compo_field.apply_pin(_self).subtree_range(dyn_index - #repeater_offset) + } + )); + repeated_subtree_components.push(quote!( + #repeater_offset..=#last_repeater => { + #sub_compo_field.apply_pin(_self).subtree_component(dyn_index - #repeater_offset, subtree_index, result) + } + )); } sub_component_names.push(field_name); @@ -736,6 +766,18 @@ fn generate_sub_component( let visibility = core::ptr::eq(&root.item_tree.root as *const _, component as *const _).then(|| quote!(pub)); + let access_prop = |&property_index| { + access_member( + &llr::PropertyReference::Local { sub_component_path: vec![], property_index }, + &ctx, + ) + }; + let prop = index_property.iter().map(access_prop); + let mut subtree_index_function = quote!(#(#prop.get() as usize)*); + if subtree_index_function.is_empty() { + subtree_index_function = quote!(core::usize::MAX); + } + quote!( #[derive(slint::re_exports::FieldOffsets, Default)] #[const_field_offset(slint::re_exports::const_field_offset)] @@ -796,6 +838,33 @@ fn generate_sub_component( slint::re_exports::Orientation::Vertical => #layout_info_v, } } + + fn subtree_range(self: ::core::pin::Pin<&Self>, dyn_index: usize) -> slint::re_exports::IndexRange { + #![allow(unused)] + use slint::re_exports::*; + let _self = self; + match dyn_index { + #(#repeated_subtree_ranges)* + _ => panic!("invalid dyn_index {}", dyn_index), + } + } + + fn subtree_component(self: ::core::pin::Pin<&Self>, dyn_index: usize, subtree_index: usize, result: &mut slint::re_exports::ComponentWeak) { + #![allow(unused)] + use slint::re_exports::*; + let _self = self; + match dyn_index { + #(#repeated_subtree_components)* + _ => panic!("invalid dyn_index {}", dyn_index), + }; + } + + fn index_property(self: ::core::pin::Pin<&Self>) -> usize { + #![allow(unused)] + use slint::re_exports::*; + let _self = self; + #subtree_index_function + } } #(#extra_components)* @@ -923,8 +992,15 @@ fn generate_item_tree( root: &llr::PublicComponent, parent_ctx: Option, extra_fields: TokenStream, + index_property: Option, ) -> TokenStream { - let sub_comp = generate_sub_component(&sub_tree.root, root, parent_ctx.clone(), extra_fields); + let sub_comp = generate_sub_component( + &sub_tree.root, + root, + parent_ctx.clone(), + extra_fields, + index_property, + ); let inner_component_id = self::inner_component_id(&sub_tree.root); let parent_component_type = parent_ctx.iter().map(|parent| { let parent_component_id = self::inner_component_id(parent.ctx.current_sub_component.unwrap()); @@ -1077,11 +1153,29 @@ fn generate_item_tree( Self::item_tree().into() } + fn get_subtree_range( + self: ::core::pin::Pin<&Self>, index: usize) -> slint::re_exports::IndexRange + { + self.subtree_range(index) + } + + fn get_subtree_component( + self: ::core::pin::Pin<&Self>, index: usize, subtree_index: usize, result: &mut slint::re_exports::ComponentWeak) + { + self.subtree_component(index, subtree_index, result); + } + + fn subtree_index( + self: ::core::pin::Pin<&Self>) -> usize + { + self.index_property() + } + fn parent_item(self: ::core::pin::Pin<&Self>, index: usize, result: &mut slint::re_exports::ItemWeak) { if index == 0 { #( if let Some(parent) = self.parent.clone().upgrade().map(|sc| VRcMapped::origin(&sc)) { - *result = slint::re_exports::ItemRc::new(parent, #parent_item_index).parent_item(); + *result = slint::re_exports::ItemRc::new(parent, #parent_item_index).downgrade(); } )* return; @@ -1105,8 +1199,13 @@ fn generate_repeated_component( root: &llr::PublicComponent, parent_ctx: ParentCtx, ) -> TokenStream { - let component = - generate_item_tree(&repeated.sub_tree, root, Some(parent_ctx.clone()), quote!()); + let component = generate_item_tree( + &repeated.sub_tree, + root, + Some(parent_ctx.clone()), + quote!(), + repeated.index_prop, + ); let ctx = EvaluationContext { public_component: root, @@ -1120,7 +1219,7 @@ fn generate_repeated_component( let inner_component_id = self::inner_component_id(&repeated.sub_tree.root); // let rep_inner_component_id = self::inner_component_id(&repeated.sub_tree.root.name); - // let inner_component_id = self::inner_component_id(&parent_compo); + // let inner_component_id = self::inner_component_id(&parent_compo); let extra_fn = if let Some(listview) = &repeated.listview { let p_y = access_member(&listview.prop_y, &ctx); diff --git a/internal/core/component.rs b/internal/core/component.rs index 59ea0ecd9..d2db8d25c 100644 --- a/internal/core/component.rs +++ b/internal/core/component.rs @@ -1,6 +1,8 @@ // Copyright © SixtyFPS GmbH // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial +// cSpell: ignore dealloc + #![warn(missing_docs)] //! This module contains the basic datastructures that are exposed to the C API @@ -12,6 +14,15 @@ use crate::slice::Slice; use crate::window::WindowRc; use vtable::*; +#[repr(C)] +/// A range of indices +pub struct IndexRange { + /// Start index + pub start: usize, + /// Index one past the last index + pub end: usize, +} + /// A Component is representing an unit that is allocated together #[vtable] #[repr(C)] @@ -32,17 +43,35 @@ pub struct ComponentVTable { index: usize, ) -> core::pin::Pin>, + /// Return the range of indices below the dynamic `ItemTreeNode` at `index` + pub get_subtree_range: + extern "C" fn(core::pin::Pin>, index: usize) -> IndexRange, + + /// Return the `ComponentRc` at `subindex` below the dynamic `ItemTreeNode` at `index` + pub get_subtree_component: extern "C" fn( + core::pin::Pin>, + index: usize, + subindex: usize, + result: &mut vtable::VWeak, + ), + /// Return the item tree that is defined by this `Component`. /// The return value is an item weak because it can be null if there is no parent. /// And the return value is passed by &mut because ItemWeak has a destructor pub get_item_tree: extern "C" fn(core::pin::Pin>) -> Slice, + // FIXME: This does return an invalid ItemWeak now that points to the parent repeater! + // FIXME: Get rid of the index and make this always return the "Item" that connects this component + // to its parent-component? /// Return the parent item. /// The return value is an item weak because it can be null if there is no parent. /// And the return value is passed by &mut because ItemWeak has a destructor pub parent_item: extern "C" fn(core::pin::Pin>, index: usize, result: &mut ItemWeak), + /// Return the index of the current subtree or usize::MAX if this is not a subtree + pub subtree_index: extern "C" fn(core::pin::Pin>) -> usize, + /// Returns the layout info for this component pub layout_info: extern "C" fn(core::pin::Pin>, Orientation) -> LayoutInfo, diff --git a/internal/core/items.rs b/internal/core/items.rs index 319084f40..5ec1de550 100644 --- a/internal/core/items.rs +++ b/internal/core/items.rs @@ -1,6 +1,8 @@ // Copyright © SixtyFPS GmbH // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial +// cSpell: ignore dealloc nesw + /*! This module contains the builtin items, either in this file or in sub-modules. @@ -177,6 +179,7 @@ impl ItemRc { pub fn new(component: vtable::VRc, index: usize) -> Self { Self { component, index } } + /// Return a `Pin>` pub fn borrow<'a>(&'a self) -> Pin> { let comp_ref_pin = vtable::VRc::borrow_pin(&self.component); @@ -185,15 +188,29 @@ impl ItemRc { // lifetime of the component, which is 'a. Pin::as_ref removes the lifetime, but we can just put it back. unsafe { core::mem::transmute::>, Pin>>(result) } } + pub fn downgrade(&self) -> ItemWeak { ItemWeak { component: VRc::downgrade(&self.component), index: self.index } } + /// Return the parent Item in the item tree. /// This is weak because it can be null if there is no parent pub fn parent_item(&self) -> ItemWeak { let comp_ref_pin = vtable::VRc::borrow_pin(&self.component); + let item_tree = crate::item_tree::ComponentItemTree::new( + comp_ref_pin.as_ref().get_item_tree().as_slice(), + ); + + if let Some(parent_index) = item_tree.parent(self.index) { + return ItemRc::new(self.component.clone(), parent_index).downgrade(); + } + let mut r = ItemWeak::default(); comp_ref_pin.as_ref().parent_item(self.index, &mut r); + // parent_item returns the repeater node, go up one more level! + if let Some(rc) = r.upgrade() { + r = rc.parent_item(); + } r } diff --git a/internal/core/model.rs b/internal/core/model.rs index 23c247472..b788bcc43 100644 --- a/internal/core/model.rs +++ b/internal/core/model.rs @@ -1,12 +1,15 @@ // Copyright © SixtyFPS GmbH // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial +// cSpell: ignore vecmodel + //! Model and Repeater // Safety: we use pointer to Repeater in the DependencyList, bue the Drop of the Repeater // will remove them from the list so it will not be accessed after it is dropped #![allow(unsafe_code)] +use crate::component::ComponentVTable; use crate::item_tree::TraversalOrder; use crate::items::ItemRef; use crate::layout::Orientation; @@ -567,7 +570,9 @@ impl Model for ModelRc { } /// Component that can be instantiated by a repeater. -pub trait RepeatedComponent: crate::component::Component { +pub trait RepeatedComponent: + crate::component::Component + vtable::HasStaticVTable + 'static +{ /// The data corresponding to the model type Data: 'static; @@ -615,6 +620,7 @@ impl Default for RepeaterInner { RepeaterInner { components: Default::default(), offset: 0, cached_item_height: 0. } } } + trait ErasedRepeater { fn row_changed(&self, row: usize); fn row_added(&self, index: usize, count: usize); @@ -968,7 +974,24 @@ impl Repeater { self.inner.borrow().components.len() } - /// Return true if the Repeater is empty + /// Return the range of indices used by this Repeater. + /// + /// Two values are necessary here since the Repeater can start to insert the data from its + /// model at an offset. + pub fn range(&self) -> (usize, usize) { + let inner = self.inner.borrow(); + (inner.offset, inner.offset + inner.components.len()) + } + + pub fn component_at(&self, index: usize) -> Option> { + self.inner + .borrow() + .components + .get(index) + .map(|c| c.1.clone().expect("That was updated before!")) + } + + /// Return true if the Repeater as empty pub fn is_empty(&self) -> bool { self.len() == 0 } diff --git a/internal/interpreter/dynamic_component.rs b/internal/interpreter/dynamic_component.rs index ee88d12b0..0395d0116 100644 --- a/internal/interpreter/dynamic_component.rs +++ b/internal/interpreter/dynamic_component.rs @@ -1,6 +1,8 @@ // Copyright © SixtyFPS GmbH // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial +// cSpell: ignore dealloc refcell unerase + use crate::{api::Value, dynamic_type, eval}; use core::convert::TryInto; @@ -12,7 +14,9 @@ use i_slint_compiler::object_tree::ElementRc; use i_slint_compiler::*; use i_slint_compiler::{diagnostics::BuildDiagnostics, object_tree::PropertyDeclaration}; use i_slint_core::api::Window; -use i_slint_core::component::{Component, ComponentRef, ComponentRefPin, ComponentVTable}; +use i_slint_core::component::{ + Component, ComponentRef, ComponentRefPin, ComponentVTable, ComponentWeak, IndexRange, +}; use i_slint_core::item_tree::{ ItemTreeNode, ItemVisitorRefMut, ItemVisitorVTable, TraversalOrder, VisitChildrenResult, }; @@ -174,9 +178,26 @@ impl Component for ErasedComponentBox { unsafe { get_item_ref(self.get_ref().borrow(), index) } } + fn get_subtree_range(self: Pin<&Self>, index: usize) -> IndexRange { + self.borrow().as_ref().get_subtree_range(index) + } + + fn get_subtree_component( + self: Pin<&Self>, + index: usize, + subindex: usize, + result: &mut ComponentWeak, + ) { + self.borrow().as_ref().get_subtree_component(index, subindex, result); + } + fn parent_item(self: Pin<&Self>, index: usize, result: &mut ItemWeak) { self.borrow().as_ref().parent_item(index, result) } + + fn subtree_index(self: Pin<&Self>) -> usize { + self.borrow().as_ref().subtree_index() + } } i_slint_core::ComponentVTable_static!(static COMPONENT_BOX_VT for ErasedComponentBox); @@ -1030,7 +1051,10 @@ pub(crate) fn generate_component<'id>( layout_info, get_item_ref, get_item_tree, + get_subtree_range, + get_subtree_component, parent_item, + subtree_index, drop_in_place, dealloc, }; @@ -1518,6 +1542,34 @@ unsafe extern "C" fn get_item_ref(component: ComponentRefPin, index: usize) -> P } } +extern "C" fn get_subtree_range(component: ComponentRefPin, index: usize) -> IndexRange { + generativity::make_guard!(guard); + let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) }; + let rep_in_comp = unsafe { instance_ref.component_type.repeater[index].get_untagged() }; + ensure_repeater_updated(instance_ref, rep_in_comp); + + let repeater = rep_in_comp.offset.apply(&instance_ref.instance); + let (start, end) = repeater.range(); + IndexRange { start, end } +} + +extern "C" fn get_subtree_component( + component: ComponentRefPin, + index: usize, + subtree_index: usize, + result: &mut ComponentWeak, +) { + generativity::make_guard!(guard); + let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) }; + let rep_in_comp = unsafe { instance_ref.component_type.repeater[index].get_untagged() }; + ensure_repeater_updated(instance_ref, rep_in_comp); + + let repeater = rep_in_comp.offset.apply(&instance_ref.instance); + *result = vtable::VRc::downgrade(&vtable::VRc::into_dyn( + repeater.component_at(subtree_index).unwrap(), + )) +} + extern "C" fn get_item_tree(component: ComponentRefPin) -> Slice { generativity::make_guard!(guard); let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) }; @@ -1525,6 +1577,16 @@ extern "C" fn get_item_tree(component: ComponentRefPin) -> Slice { unsafe { core::mem::transmute::<&[ItemTreeNode], &[ItemTreeNode]>(tree) }.into() } +extern "C" fn subtree_index(component: ComponentRefPin) -> usize { + generativity::make_guard!(guard); + let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) }; + if let Ok(value) = instance_ref.component_type.get_property(component, "index") { + value.try_into().unwrap() + } else { + core::usize::MAX + } +} + unsafe extern "C" fn parent_item(component: ComponentRefPin, index: usize, result: &mut ItemWeak) { generativity::make_guard!(guard); let instance_ref = InstanceRef::from_pin_ref(component, guard); @@ -1549,7 +1611,7 @@ unsafe extern "C" fn parent_item(component: ComponentRefPin, index: usize, resul .into_dyn() .upgrade() .unwrap(); - *result = ItemRc::new(parent_rc, parent_index).parent_item(); + *result = ItemRc::new(parent_rc, parent_index).downgrade(); }; } return;