use super::{EvaluationContext, Expression, ParentCtx};
use crate::langtype::{NativeClass, Type};
use std::cell::{Cell, RefCell};
use std::collections::{BTreeMap, HashMap};
use std::num::NonZeroUsize;
use std::rc::Rc;
pub type PropertyIndex = usize;
#[derive(Debug, Clone, derive_more::Deref)]
pub struct MutExpression(RefCell<Expression>);
impl From<Expression> for MutExpression {
fn from(e: Expression) -> Self {
Self(e.into())
}
}
impl MutExpression {
pub fn visit_recursive(&self, visitor: &mut dyn FnMut(&Expression)) {
self.0.borrow().visit_recursive(visitor)
}
pub fn ty(&self, ctx: &dyn super::TypeResolutionContext) -> Type {
self.0.borrow().ty(ctx)
}
}
#[derive(Debug, Clone)]
pub enum Animation {
Static(Expression),
Transition(Expression),
}
#[derive(Debug, Clone)]
pub struct BindingExpression {
pub expression: MutExpression,
pub animation: Option<Animation>,
pub is_constant: bool,
pub is_state_info: bool,
pub use_count: Cell<usize>,
}
#[derive(Debug)]
pub struct GlobalComponent {
pub name: String,
pub properties: Vec<Property>,
pub functions: Vec<Function>,
pub init_values: Vec<Option<BindingExpression>>,
pub const_properties: Vec<bool>,
pub public_properties: PublicProperties,
pub private_properties: PrivateProperties,
pub exported: bool,
pub aliases: Vec<String>,
pub is_builtin: bool,
pub prop_analysis: Vec<crate::object_tree::PropertyAnalysis>,
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub enum PropertyReference {
Local { sub_component_path: Vec<usize>, property_index: PropertyIndex },
InNativeItem { sub_component_path: Vec<usize>, item_index: usize, prop_name: String },
InParent { level: NonZeroUsize, parent_reference: Box<PropertyReference> },
Global { global_index: usize, property_index: usize },
Function { sub_component_path: Vec<usize>, function_index: usize },
GlobalFunction { global_index: usize, function_index: usize },
}
#[derive(Debug, Default)]
pub struct Property {
pub name: String,
pub ty: Type,
pub use_count: Cell<usize>,
}
#[derive(Debug)]
pub struct Function {
pub name: String,
pub ret_ty: Type,
pub args: Vec<Type>,
pub code: Expression,
}
#[derive(Debug, Clone)]
pub struct ListViewInfo {
pub viewport_y: PropertyReference,
pub viewport_height: PropertyReference,
pub viewport_width: PropertyReference,
pub listview_height: PropertyReference,
pub listview_width: PropertyReference,
pub prop_y: PropertyReference,
pub prop_width: PropertyReference,
pub prop_height: PropertyReference,
}
#[derive(Debug)]
pub struct RepeatedElement {
pub model: MutExpression,
pub index_prop: Option<PropertyIndex>,
pub data_prop: Option<PropertyIndex>,
pub sub_tree: ItemTree,
pub index_in_tree: usize,
pub listview: Option<ListViewInfo>,
}
#[derive(Clone, Debug)]
pub struct ComponentContainerIndex(usize);
impl From<usize> for ComponentContainerIndex {
fn from(value: usize) -> Self {
assert!(value < ComponentContainerIndex::MAGIC);
ComponentContainerIndex(value + ComponentContainerIndex::MAGIC)
}
}
impl ComponentContainerIndex {
const MAGIC: usize = (usize::MAX / 2) + 1;
pub fn as_item_tree_index(&self) -> usize {
assert!(self.0 >= ComponentContainerIndex::MAGIC);
self.0 - ComponentContainerIndex::MAGIC
}
pub fn as_repeater_index(&self) -> usize {
assert!(self.0 >= ComponentContainerIndex::MAGIC);
self.0
}
pub fn try_from_repeater_index(index: usize) -> Option<Self> {
if index >= ComponentContainerIndex::MAGIC {
Some(ComponentContainerIndex(index))
} else {
None
}
}
}
#[derive(Debug)]
pub struct ComponentContainerElement {
pub component_container_item_tree_index: ComponentContainerIndex,
pub component_container_items_index: usize,
pub component_placeholder_item_tree_index: usize,
}
pub struct Item {
pub ty: Rc<NativeClass>,
pub name: String,
pub index_in_tree: usize,
pub is_flickable_viewport: bool,
}
impl std::fmt::Debug for Item {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Item")
.field("ty", &self.ty.class_name)
.field("name", &self.name)
.field("index_in_tree", &self.index_in_tree)
.field("is_flickable_viewport", &self.is_flickable_viewport)
.finish()
}
}
#[derive(Debug)]
pub struct TreeNode {
pub sub_component_path: Vec<usize>,
pub item_index: usize,
pub repeated: bool,
pub children: Vec<TreeNode>,
pub is_accessible: bool,
}
impl TreeNode {
fn children_count(&self) -> usize {
let mut count = self.children.len();
for c in &self.children {
count += c.children_count();
}
count
}
pub fn visit_in_array(
&self,
visitor: &mut dyn FnMut(
&TreeNode,
usize,
usize,
),
) {
visitor(self, 1, 0);
visit_in_array_recursive(self, 1, 0, visitor);
fn visit_in_array_recursive(
node: &TreeNode,
children_offset: usize,
current_index: usize,
visitor: &mut dyn FnMut(&TreeNode, usize, usize),
) {
let mut offset = children_offset + node.children.len();
for c in &node.children {
visitor(c, offset, current_index);
offset += c.children_count();
}
let mut offset = children_offset + node.children.len();
for (i, c) in node.children.iter().enumerate() {
visit_in_array_recursive(c, offset, children_offset + i, visitor);
offset += c.children_count();
}
}
}
}
#[derive(Debug)]
pub struct SubComponent {
pub name: String,
pub properties: Vec<Property>,
pub functions: Vec<Function>,
pub items: Vec<Item>,
pub repeated: Vec<RepeatedElement>,
pub component_containers: Vec<ComponentContainerElement>,
pub popup_windows: Vec<ItemTree>,
pub sub_components: Vec<SubComponentInstance>,
pub property_init: Vec<(PropertyReference, BindingExpression)>,
pub animations: HashMap<PropertyReference, Expression>,
pub two_way_bindings: Vec<(PropertyReference, PropertyReference)>,
pub const_properties: Vec<PropertyReference>,
pub init_code: Vec<MutExpression>,
pub layout_info_h: MutExpression,
pub layout_info_v: MutExpression,
pub accessible_prop: BTreeMap<(usize, String), MutExpression>,
pub prop_analysis: HashMap<PropertyReference, PropAnalysis>,
}
#[derive(Debug, Clone)]
pub struct PropAnalysis {
pub property_init: Option<usize>,
pub analysis: crate::object_tree::PropertyAnalysis,
}
impl SubComponent {
pub fn repeater_count(&self) -> usize {
let mut count = self.repeated.len();
for x in self.sub_components.iter() {
count += x.ty.repeater_count();
}
count
}
pub fn child_item_count(&self) -> usize {
let mut count = self.items.len();
for x in self.sub_components.iter() {
count += x.ty.child_item_count();
}
count
}
}
pub struct SubComponentInstance {
pub ty: Rc<SubComponent>,
pub name: String,
pub index_in_tree: usize,
pub index_of_first_child_in_tree: usize,
pub repeater_offset: usize,
}
impl std::fmt::Debug for SubComponentInstance {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SubComponentInstance")
.field("ty", &self.ty.name)
.field("name", &self.name)
.field("index_in_tree", &self.index_in_tree)
.field("index_of_first_child_in_tree", &self.index_of_first_child_in_tree)
.field("repeater_offset", &self.repeater_offset)
.finish()
}
}
#[derive(Debug)]
pub struct ItemTree {
pub root: SubComponent,
pub tree: TreeNode,
pub parent_context: Option<String>,
}
#[derive(Debug)]
pub struct PublicComponent {
pub public_properties: PublicProperties,
pub private_properties: PrivateProperties,
pub item_tree: ItemTree,
pub sub_components: Vec<Rc<SubComponent>>,
pub globals: Vec<GlobalComponent>,
}
impl PublicComponent {
pub fn for_each_sub_components<'a>(
&'a self,
visitor: &mut dyn FnMut(&'a SubComponent, &EvaluationContext<'_>),
) {
fn visit_component<'a>(
root: &'a PublicComponent,
c: &'a SubComponent,
visitor: &mut dyn FnMut(&'a SubComponent, &EvaluationContext<'_>),
parent: Option<ParentCtx<'_>>,
) {
let ctx = EvaluationContext::new_sub_component(root, c, (), parent);
visitor(c, &ctx);
for (idx, r) in c.repeated.iter().enumerate() {
visit_component(
root,
&r.sub_tree.root,
visitor,
Some(ParentCtx::new(&ctx, Some(idx))),
);
}
for x in &c.popup_windows {
visit_component(root, &x.root, visitor, Some(ParentCtx::new(&ctx, None)));
}
}
for c in &self.sub_components {
visit_component(self, c, visitor, None);
}
visit_component(self, &self.item_tree.root, visitor, None);
}
pub fn for_each_expression<'a>(
&'a self,
visitor: &mut dyn FnMut(&'a super::MutExpression, &EvaluationContext<'_>),
) {
self.for_each_sub_components(&mut |sc, ctx| {
for e in &sc.init_code {
visitor(e, ctx);
}
for (_, e) in &sc.property_init {
visitor(&e.expression, ctx);
}
visitor(&sc.layout_info_h, ctx);
visitor(&sc.layout_info_v, ctx);
for e in sc.accessible_prop.values() {
visitor(e, ctx);
}
});
for g in &self.globals {
let ctx = EvaluationContext::new_global(self, g, ());
for e in g.init_values.iter().filter_map(|x| x.as_ref()) {
visitor(&e.expression, &ctx)
}
}
}
}
#[derive(Debug, Clone)]
pub struct PublicProperty {
pub name: String,
pub ty: Type,
pub prop: PropertyReference,
pub read_only: bool,
}
pub type PublicProperties = Vec<PublicProperty>;
pub type PrivateProperties = Vec<(String, Type)>;