From 9488f42749ba96a29cf1a1ac052f224abc70599e Mon Sep 17 00:00:00 2001 From: nathan Date: Sun, 4 Dec 2022 15:23:24 +0800 Subject: [PATCH] chore: macro node --- shared-lib/flowy-ast/src/ast.rs | 2 +- shared-lib/flowy-ast/src/event_attrs.rs | 4 +- shared-lib/flowy-ast/src/lib.rs | 3 - shared-lib/flowy-ast/src/node_attrs.rs | 33 ++- shared-lib/flowy-ast/src/symbol.rs | 1 + shared-lib/flowy-ast/src/ty_ext.rs | 4 +- .../flowy-codegen/src/dart_event/ast.rs | 1 + shared-lib/flowy-codegen/src/lib.rs | 3 - shared-lib/flowy-derive/src/node/mod.rs | 51 +++-- .../flowy-sync/src/client_folder/app_node.rs | 95 -------- .../src/client_folder/folder_node.rs | 206 +++++++++--------- .../src/client_folder/folder_node_2.rs | 51 ----- .../flowy-sync/src/client_folder/mod.rs | 7 +- .../src/client_folder/trash_node.rs | 20 ++ .../flowy-sync/src/client_folder/util.rs | 14 +- .../flowy-sync/src/client_folder/view_node.rs | 44 ---- .../src/client_folder/workspace_node.rs | 142 +++++------- .../src/client_folder/workspace_node_2.rs | 43 ---- .../tests/client_folder/folder_test.rs | 57 ++--- .../flowy-sync/tests/client_folder/script.rs | 70 +++--- .../tests/client_folder/workspace_test.rs | 35 ++- .../grid-rev-model/src/grid_setting_rev.rs | 6 +- shared-lib/lib-ot/src/core/node_tree/tree.rs | 2 +- 23 files changed, 323 insertions(+), 571 deletions(-) delete mode 100644 shared-lib/flowy-sync/src/client_folder/app_node.rs delete mode 100644 shared-lib/flowy-sync/src/client_folder/folder_node_2.rs create mode 100644 shared-lib/flowy-sync/src/client_folder/trash_node.rs delete mode 100644 shared-lib/flowy-sync/src/client_folder/view_node.rs delete mode 100644 shared-lib/flowy-sync/src/client_folder/workspace_node_2.rs diff --git a/shared-lib/flowy-ast/src/ast.rs b/shared-lib/flowy-ast/src/ast.rs index 44616cb15e..5f344d1597 100644 --- a/shared-lib/flowy-ast/src/ast.rs +++ b/shared-lib/flowy-ast/src/ast.rs @@ -4,7 +4,7 @@ use crate::event_attrs::EventEnumAttrs; use crate::node_attrs::NodeStructAttrs; -use crate::{is_recognizable_field, pb_attrs, ty_ext::*, ASTResult, PBAttrsContainer, PBStructAttrs, NODE_TYPE}; +use crate::{is_recognizable_field, ty_ext::*, ASTResult, PBAttrsContainer, PBStructAttrs, NODE_TYPE}; use proc_macro2::Ident; use syn::Meta::NameValue; use syn::{self, punctuated::Punctuated}; diff --git a/shared-lib/flowy-ast/src/event_attrs.rs b/shared-lib/flowy-ast/src/event_attrs.rs index a9684b981b..8c5739dd19 100644 --- a/shared-lib/flowy-ast/src/event_attrs.rs +++ b/shared-lib/flowy-ast/src/event_attrs.rs @@ -1,10 +1,8 @@ use crate::{get_event_meta_items, parse_lit_str, symbol::*, ASTResult}; - use syn::{ self, - parse::{self, Parse}, - Meta::{List, NameValue, Path}, + Meta::{NameValue, Path}, NestedMeta::{Lit, Meta}, }; diff --git a/shared-lib/flowy-ast/src/lib.rs b/shared-lib/flowy-ast/src/lib.rs index 5529177f04..7d5e8b8e41 100644 --- a/shared-lib/flowy-ast/src/lib.rs +++ b/shared-lib/flowy-ast/src/lib.rs @@ -1,9 +1,6 @@ #[macro_use] extern crate syn; -#[macro_use] -extern crate quote; - mod ast; mod ctxt; mod pb_attrs; diff --git a/shared-lib/flowy-ast/src/node_attrs.rs b/shared-lib/flowy-ast/src/node_attrs.rs index 3c14c0a426..7f2c062aca 100644 --- a/shared-lib/flowy-ast/src/node_attrs.rs +++ b/shared-lib/flowy-ast/src/node_attrs.rs @@ -1,11 +1,8 @@ -use crate::{get_node_meta_items, get_pb_meta_items, parse_lit_into_expr_path, symbol::*, ASTAttr, ASTResult}; -use proc_macro2::{Group, Ident, Span, TokenStream, TokenTree}; +use crate::{get_node_meta_items, parse_lit_into_expr_path, symbol::*, ASTAttr, ASTResult}; use quote::ToTokens; use syn::{ - self, - parse::{self, Parse}, - LitStr, - Meta::{List, NameValue, Path}, + self, LitStr, + Meta::NameValue, NestedMeta::{Lit, Meta}, }; @@ -14,18 +11,20 @@ pub struct NodeStructAttrs { pub has_child: bool, pub child_name: Option, pub child_index: Option, - get_node_value_with: Option, - set_node_value_with: Option, + pub get_node_value_with: Option, + pub set_node_value_with: Option, + pub with_children: Option, } impl NodeStructAttrs { /// Extract out the `#[node(...)]` attributes from a struct field. - pub fn from_ast(ast_result: &ASTResult, index: usize, field: &syn::Field) -> Self { + pub fn from_ast(ast_result: &ASTResult, _index: usize, field: &syn::Field) -> Self { let mut rename = ASTAttr::none(ast_result, RENAME_NODE); let mut child_name = ASTAttr::none(ast_result, CHILD_NODE_NAME); let mut child_index = ASTAttr::none(ast_result, CHILD_NODE_INDEX); let mut get_node_value_with = ASTAttr::none(ast_result, GET_NODE_VALUE_WITH); let mut set_node_value_with = ASTAttr::none(ast_result, SET_NODE_VALUE_WITH); + let mut with_children = ASTAttr::none(ast_result, WITH_CHILDREN); for meta_item in field .attrs @@ -69,6 +68,13 @@ impl NodeStructAttrs { } } + // Parse `#[node(with_children= "...")]` + Meta(NameValue(m)) if m.path == WITH_CHILDREN => { + if let Ok(path) = parse_lit_into_expr_path(ast_result, WITH_CHILDREN, &m.lit) { + with_children.set(&m.path, path); + } + } + Meta(meta_item) => { let path = meta_item.path().into_token_stream().to_string().replace(' ', ""); ast_result.error_spanned_by(meta_item.path(), format!("unknown node field attribute `{}`", path)); @@ -87,14 +93,7 @@ impl NodeStructAttrs { child_name, get_node_value_with: get_node_value_with.get(), set_node_value_with: set_node_value_with.get(), + with_children: with_children.get(), } } - - pub fn set_node_value_with(&self) -> Option<&syn::ExprPath> { - self.set_node_value_with.as_ref() - } - - pub fn get_node_value_with(&self) -> Option<&syn::ExprPath> { - self.get_node_value_with.as_ref() - } } diff --git a/shared-lib/flowy-ast/src/symbol.rs b/shared-lib/flowy-ast/src/symbol.rs index c3455a1e4b..b0d1bd9ada 100644 --- a/shared-lib/flowy-ast/src/symbol.rs +++ b/shared-lib/flowy-ast/src/symbol.rs @@ -45,6 +45,7 @@ pub const GET_NODE_VALUE_WITH: Symbol = Symbol("get_value_with"); pub const SET_NODE_VALUE_WITH: Symbol = Symbol("set_value_with"); pub const GET_VEC_ELEMENT_WITH: Symbol = Symbol("get_element_with"); pub const GET_MUT_VEC_ELEMENT_WITH: Symbol = Symbol("get_mut_element_with"); +pub const WITH_CHILDREN: Symbol = Symbol("with_children"); impl PartialEq for Ident { fn eq(&self, word: &Symbol) -> bool { diff --git a/shared-lib/flowy-ast/src/ty_ext.rs b/shared-lib/flowy-ast/src/ty_ext.rs index 4c1364c89d..6da5054ebb 100644 --- a/shared-lib/flowy-ast/src/ty_ext.rs +++ b/shared-lib/flowy-ast/src/ty_ext.rs @@ -62,7 +62,9 @@ pub fn parse_ty<'a>(ast_result: &ASTResult, ty: &'a syn::Type) -> Result generate_vec_ty_info(ast_result, seg, bracketed), "Option" => generate_option_ty_info(ast_result, ty, seg, bracketed), _ => { - return Err(format!("Unsupported ty {}", seg.ident)); + let msg = format!("Unsupported type: {}", seg.ident); + ast_result.error_spanned_by(&seg.ident, &msg); + return Err(msg); } } } else { diff --git a/shared-lib/flowy-codegen/src/dart_event/ast.rs b/shared-lib/flowy-codegen/src/dart_event/ast.rs index 1ae3a2bff4..141faaba51 100644 --- a/shared-lib/flowy-codegen/src/dart_event/ast.rs +++ b/shared-lib/flowy-codegen/src/dart_event/ast.rs @@ -1,4 +1,5 @@ use flowy_ast::EventEnumAttrs; +use quote::format_ident; pub struct EventASTContext { pub event: syn::Ident, diff --git a/shared-lib/flowy-codegen/src/lib.rs b/shared-lib/flowy-codegen/src/lib.rs index 7c4bec0a1e..7f01c9ef08 100644 --- a/shared-lib/flowy-codegen/src/lib.rs +++ b/shared-lib/flowy-codegen/src/lib.rs @@ -15,6 +15,3 @@ pub struct ProtoCache { pub structs: Vec, pub enums: Vec, } - -#[macro_use] -extern crate quote; diff --git a/shared-lib/flowy-derive/src/node/mod.rs b/shared-lib/flowy-derive/src/node/mod.rs index 0ea8cc0191..3058a6d460 100644 --- a/shared-lib/flowy-derive/src/node/mod.rs +++ b/shared-lib/flowy-derive/src/node/mod.rs @@ -26,8 +26,9 @@ pub fn make_helper_funcs_token_stream(ast: &ASTContainer) -> TokenStream { let struct_ident = &ast.ident; token_streams.extend(quote! { impl #struct_ident { - pub fn get_path(&self) -> Path { - self.tree.read().path_from_node_id(self.node_id.clone()) + pub fn get_path(&self) -> Option { + let node_id = &self.node_id?; + Some(self.tree.read().path_from_node_id(node_id.clone())) } } }); @@ -50,7 +51,6 @@ pub fn make_alter_children_token_stream(ast_result: &ASTResult, ast: &ASTContain } let children_field = children_fields.first().unwrap(); let field_name = children_field.name().unwrap(); - eprintln!("😄 {:?} {:?}", struct_ident, field_name); let child_name = children_field.node_attrs.child_name.as_ref().unwrap(); let get_func_name = format_ident!("get_{}", child_name.value()); let get_mut_func_name = format_ident!("get_mut_{}", child_name.value()); @@ -60,22 +60,26 @@ pub fn make_alter_children_token_stream(ast_result: &ASTResult, ast: &ASTContain token_streams.extend(quote! { impl #struct_ident { - pub fn #get_func_name(&self, id: &str) -> Option<&#ty> { - self.#field_name.iter().find(|element| element.id == id) + pub fn #get_func_name>(&self, id: T) -> Option<&#ty> { + let id = id.as_ref(); + self.#field_name.iter().find(|element| element.id == id) } - pub fn #get_mut_func_name(&mut self, id: &str) -> Option<&mut #ty> { - self.#field_name.iter_mut().find(|element| element.id == id) + pub fn #get_mut_func_name>(&mut self, id: T) -> Option<&mut #ty> { + let id = id.as_ref(); + self.#field_name.iter_mut().find(|element| element.id == id) } - pub fn #remove_func_name(&mut self, id: &str) { - if let Some(index) = self.#field_name.iter().position(|element| element.id == id) { + pub fn #remove_func_name>(&mut self, id: T) { + let id = id.as_ref(); + if let Some(index) = self.#field_name.iter().position(|element| element.id == id && element.node_id.is_some()) { let element = self.#field_name.remove(index); - let element_path = element.get_path(); + let element_path = element.get_path().unwrap(); let mut write_guard = self.tree.write(); let mut nodes = vec![]; - if let Some(node_data) = write_guard.get_node_data(element.node_id.clone()) { + + if let Some(node_data) = element.node_id.and_then(|node_id| write_guard.get_node_data(node_id.clone())) { nodes.push(node_data); } let _ = write_guard.apply_op(NodeOperation::Delete { @@ -85,18 +89,26 @@ pub fn make_alter_children_token_stream(ast_result: &ASTResult, ast: &ASTContain } } - pub fn #add_func_name(&mut self, value: #ty) { + pub fn #add_func_name(&mut self, mut value: #ty) -> Result<(), String> { + if self.node_id.is_none() { + return Err("The node id is empty".to_owned()); + } + let mut transaction = Transaction::new(); - let parent_path = self.get_path(); + let parent_path = self.get_path().unwrap(); + let path = parent_path.clone_with(self.#field_name.len()); let node_data = value.to_node_data(); transaction.push_operation(NodeOperation::Insert { - path, + path: path.clone(), nodes: vec![node_data], }); let _ = self.tree.write().apply_transaction(transaction); + let child_node_id = self.tree.read().node_id_at_path(path).unwrap(); + value.node_id = Some(child_node_id); self.#field_name.push(value); + Ok(()) } } }); @@ -189,21 +201,24 @@ pub fn make_get_set_value_token_steam(ast: &ASTContainer) -> Option let get_value_return_ty = field.ty; let set_value_input_ty = field.ty; - if let Some(get_value_with_fn) = field.node_attrs.get_node_value_with() { + if let Some(get_value_with_fn) = &field.node_attrs.get_node_value_with { token_streams.extend(quote! { impl #struct_ident { pub fn #get_func_name(&self) -> Option<#get_value_return_ty> { - #get_value_with_fn(self.#tree.clone(), &self.node_id, #field_name_str) + let node_id = self.node_id.as_ref()?; + #get_value_with_fn(self.#tree.clone(), node_id, #field_name_str) } } }); } - if let Some(set_value_with_fn) = field.node_attrs.set_node_value_with() { + if let Some(set_value_with_fn) = &field.node_attrs.set_node_value_with { token_streams.extend(quote! { impl #struct_ident { pub fn #set_func_name(&self, value: #set_value_input_ty) { - let _ = #set_value_with_fn(self.#tree.clone(), &self.node_id, #field_name_str, value); + if let Some(node_id) = self.node_id.as_ref() { + let _ = #set_value_with_fn(self.#tree.clone(), node_id, #field_name_str, value); + } } } }); diff --git a/shared-lib/flowy-sync/src/client_folder/app_node.rs b/shared-lib/flowy-sync/src/client_folder/app_node.rs deleted file mode 100644 index 3882a65580..0000000000 --- a/shared-lib/flowy-sync/src/client_folder/app_node.rs +++ /dev/null @@ -1,95 +0,0 @@ -use crate::client_folder::view_node::ViewNode; -use crate::client_folder::{get_attributes_str_value, set_attributes_str_value, AtomicNodeTree}; -use crate::errors::CollaborateResult; -use folder_rev_model::{AppRevision, ViewRevision}; -use lib_ot::core::{NodeData, NodeDataBuilder, NodeOperation, Path, Transaction}; -use std::sync::Arc; - -#[derive(Debug, Clone)] -pub struct AppNode { - pub id: String, - tree: Arc, - pub(crate) path: Path, - views: Vec>, -} - -impl AppNode { - pub(crate) fn from_app_revision( - transaction: &mut Transaction, - revision: AppRevision, - tree: Arc, - path: Path, - ) -> CollaborateResult { - let app_id = revision.id.clone(); - let app_node = NodeDataBuilder::new("app") - .insert_attribute("id", revision.id) - .insert_attribute("name", revision.name) - .insert_attribute("workspace_id", revision.workspace_id) - .build(); - - transaction.push_operation(NodeOperation::Insert { - path: path.clone(), - nodes: vec![app_node], - }); - - let views = revision - .belongings - .into_iter() - .enumerate() - .map(|(index, app)| (path.clone_with(index), app)) - .flat_map( - |(path, app)| match ViewNode::from_view_revision(transaction, app, tree.clone(), path) { - Ok(view_node) => Some(Arc::new(view_node)), - Err(err) => { - tracing::error!("create view node failed: {:?}", err); - None - } - }, - ) - .collect::>>(); - - Ok(Self { - id: app_id, - tree, - path, - views, - }) - } - - pub fn get_name(&self) -> Option { - get_attributes_str_value(self.tree.clone(), &self.path, "name") - } - - pub fn set_name(&self, name: String) -> CollaborateResult<()> { - set_attributes_str_value(self.tree.clone(), &self.path, "name", name) - } - - fn get_workspace_id(&self) -> Option { - get_attributes_str_value(self.tree.clone(), &self.path, "workspace_id") - } - - fn set_workspace_id(&self, workspace_id: String) -> CollaborateResult<()> { - set_attributes_str_value(self.tree.clone(), &self.path, "workspace_id", workspace_id) - } - - fn get_view(&self, view_id: &str) -> Option<&Arc> { - todo!() - } - - fn get_mut_view(&mut self, view_id: &str) -> Option<&mut Arc> { - todo!() - } - - fn add_view(&mut self, revision: ViewRevision) -> CollaborateResult<()> { - let mut transaction = Transaction::new(); - let path = self.path.clone_with(self.views.len()); - let view_node = ViewNode::from_view_revision(&mut transaction, revision, self.tree.clone(), path)?; - let _ = self.tree.write().apply_transaction(transaction)?; - self.views.push(Arc::new(view_node)); - todo!() - } - - fn remove_view(&mut self, view_id: &str) { - todo!() - } -} diff --git a/shared-lib/flowy-sync/src/client_folder/folder_node.rs b/shared-lib/flowy-sync/src/client_folder/folder_node.rs index e9541236be..aabc6e6056 100644 --- a/shared-lib/flowy-sync/src/client_folder/folder_node.rs +++ b/shared-lib/flowy-sync/src/client_folder/folder_node.rs @@ -1,21 +1,53 @@ +use crate::client_folder::trash_node::TrashNode; use crate::client_folder::workspace_node::WorkspaceNode; use crate::errors::{CollaborateError, CollaborateResult}; -use folder_rev_model::{AppRevision, ViewRevision, WorkspaceRevision}; -use lib_ot::core::{ - AttributeEntry, AttributeHashMap, AttributeValue, Changeset, Node, NodeDataBuilder, NodeOperation, NodeTree, Path, - Transaction, -}; +use flowy_derive::Node; +use lib_ot::core::NodeTree; +use lib_ot::core::*; use parking_lot::RwLock; -use std::string::ToString; use std::sync::Arc; pub type AtomicNodeTree = RwLock; pub struct FolderNodePad { - tree: Arc, - // name: workspaces, index of the node, - workspaces: Vec>, - trash: Vec>, + pub tree: Arc, + pub node_id: NodeId, + pub workspaces: WorkspaceList, + pub trash: TrashList, +} + +#[derive(Clone, Node)] +#[node_type = "workspaces"] +pub struct WorkspaceList { + pub tree: Arc, + pub node_id: Option, + + #[node(child_name = "workspace")] + inner: Vec, +} + +impl std::ops::Deref for WorkspaceList { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl std::ops::DerefMut for WorkspaceList { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +#[derive(Clone, Node)] +#[node_type = "trash"] +pub struct TrashList { + pub tree: Arc, + pub node_id: Option, + + #[node(child_name = "trash")] + inner: Vec, } impl FolderNodePad { @@ -23,42 +55,27 @@ impl FolderNodePad { Self::default() } - pub fn get_workspace(&self, workspace_id: &str) -> Option<&Arc> { + pub fn get_workspace(&self, workspace_id: &str) -> Option<&WorkspaceNode> { self.workspaces.iter().find(|workspace| workspace.id == workspace_id) } - pub fn get_mut_workspace(&mut self, workspace_id: &str) -> Option<&mut Arc> { + pub fn get_mut_workspace(&mut self, workspace_id: &str) -> Option<&mut WorkspaceNode> { self.workspaces .iter_mut() .find(|workspace| workspace.id == workspace_id) } - pub fn remove_workspace(&mut self, workspace_id: &str) { - if let Some(workspace) = self.workspaces.iter().find(|workspace| workspace.id == workspace_id) { - let mut write_guard = self.tree.write(); - let mut nodes = vec![]; + pub fn add_workspace(&mut self, mut workspace: WorkspaceNode) { + let path = workspaces_path().clone_with(self.workspaces.len()); + let op = NodeOperation::Insert { + path: path.clone(), + nodes: vec![workspace.to_node_data()], + }; + self.tree.write().apply_op(op).unwrap(); - if let Some(node_data) = write_guard.get_node_data_at_path(&workspace.path) { - nodes.push(node_data); - } - let _ = write_guard.apply_op(NodeOperation::Delete { - path: workspace.path.clone(), - nodes, - }); - } - } - - pub fn add_workspace(&mut self, revision: WorkspaceRevision) -> CollaborateResult<()> { - let mut transaction = Transaction::new(); - let node = WorkspaceNode::from_workspace_revision( - &mut transaction, - revision, - self.tree.clone(), - workspaces_path().clone_with(self.workspaces.len()), - )?; - let _ = self.tree.write().apply_transaction(transaction)?; - self.workspaces.push(Arc::new(node)); - Ok(()) + let node_id = self.tree.read().node_id_at_path(path).unwrap(); + workspace.node_id = Some(node_id); + self.workspaces.push(workspace); } pub fn to_json(&self, pretty: bool) -> CollaborateResult { @@ -69,6 +86,49 @@ impl FolderNodePad { } } +impl std::default::Default for FolderNodePad { + fn default() -> Self { + let tree = Arc::new(RwLock::new(NodeTree::default())); + + // Workspace + let mut workspaces = WorkspaceList { + tree: tree.clone(), + node_id: None, + inner: vec![], + }; + let workspace_node = workspaces.to_node_data(); + + // Trash + let mut trash = TrashList { + tree: tree.clone(), + node_id: None, + inner: vec![], + }; + let trash_node = trash.to_node_data(); + + let folder_node = NodeDataBuilder::new("folder") + .add_node_data(workspace_node) + .add_node_data(trash_node) + .build(); + + let operation = NodeOperation::Insert { + path: folder_path(), + nodes: vec![folder_node], + }; + let _ = tree.write().apply_op(operation).unwrap(); + let node_id = tree.read().node_id_at_path(folder_path()).unwrap(); + workspaces.node_id = Some(tree.read().node_id_at_path(workspaces_path()).unwrap()); + trash.node_id = Some(tree.read().node_id_at_path(trash_path()).unwrap()); + + Self { + tree, + node_id, + workspaces, + trash, + } + } +} + fn folder_path() -> Path { vec![0].into() } @@ -80,75 +140,3 @@ fn workspaces_path() -> Path { fn trash_path() -> Path { folder_path().clone_with(1) } - -pub fn get_attributes(tree: Arc, path: &Path) -> Option { - tree.read() - .get_node_at_path(&path) - .and_then(|node| Some(node.attributes.clone())) -} - -pub fn get_attributes_value(tree: Arc, path: &Path, key: &str) -> Option { - tree.read() - .get_node_at_path(&path) - .and_then(|node| node.attributes.get(key).cloned()) -} - -pub fn get_attributes_str_value(tree: Arc, path: &Path, key: &str) -> Option { - tree.read() - .get_node_at_path(&path) - .and_then(|node| node.attributes.get(key).cloned()) - .and_then(|value| value.str_value()) -} - -pub fn set_attributes_str_value( - tree: Arc, - path: &Path, - key: &str, - value: String, -) -> CollaborateResult<()> { - let old_attributes = match get_attributes(tree.clone(), path) { - None => AttributeHashMap::new(), - Some(attributes) => attributes, - }; - let mut new_attributes = old_attributes.clone(); - new_attributes.insert(key, value); - - let update_operation = NodeOperation::Update { - path: path.clone(), - changeset: Changeset::Attributes { - new: new_attributes, - old: old_attributes, - }, - }; - let _ = tree.write().apply_op(update_operation)?; - Ok(()) -} - -impl std::default::Default for FolderNodePad { - fn default() -> Self { - let workspace_node = NodeDataBuilder::new("workspaces").build(); - let trash_node = NodeDataBuilder::new("trash").build(); - let folder_node = NodeDataBuilder::new("folder") - .add_node_data(workspace_node) - .add_node_data(trash_node) - .build(); - - let operation = NodeOperation::Insert { - path: folder_path(), - nodes: vec![folder_node], - }; - let mut tree = NodeTree::default(); - let _ = tree.apply_op(operation).unwrap(); - - Self { - tree: Arc::new(RwLock::new(tree)), - workspaces: vec![], - trash: vec![], - } - } -} - -pub struct TrashNode { - tree: Arc, - parent_path: Path, -} diff --git a/shared-lib/flowy-sync/src/client_folder/folder_node_2.rs b/shared-lib/flowy-sync/src/client_folder/folder_node_2.rs deleted file mode 100644 index 19d41a0ffb..0000000000 --- a/shared-lib/flowy-sync/src/client_folder/folder_node_2.rs +++ /dev/null @@ -1,51 +0,0 @@ -use crate::client_folder::workspace_node_2::WorkspaceNode2; -use crate::errors::{CollaborateError, CollaborateResult}; -use flowy_derive::Node; -use lib_ot::core::NodeTree; -use lib_ot::core::*; -use parking_lot::RwLock; -use std::sync::Arc; - -pub type AtomicNodeTree = RwLock; - -#[derive(Node)] -#[node_type = "folder"] -pub struct FolderNodePad2 { - tree: Arc, - node_id: NodeId, - // name: workspaces, index of the node, - #[node(child_name = "child")] - children: Vec>, -} - -impl FolderNodePad2 { - pub fn new() -> Self { - // let workspace_node = NodeDataBuilder::new("workspaces").build(); - // let trash_node = NodeDataBuilder::new("trash").build(); - // let folder_node = NodeDataBuilder::new("folder") - // .add_node_data(workspace_node) - // .add_node_data(trash_node) - // .build(); - // - // let operation = NodeOperation::Insert { - // path: folder_path(), - // nodes: vec![folder_node], - // }; - // let mut tree = NodeTree::default(); - // let _ = tree.apply_op(operation).unwrap(); - // - // Self { - // tree: Arc::new(RwLock::new(tree)), - // workspaces: vec![], - // trash: vec![], - // } - todo!() - } - - pub fn to_json(&self, pretty: bool) -> CollaborateResult { - self.tree - .read() - .to_json(pretty) - .map_err(|e| CollaborateError::serde().context(e)) - } -} diff --git a/shared-lib/flowy-sync/src/client_folder/mod.rs b/shared-lib/flowy-sync/src/client_folder/mod.rs index ba42b98317..355880c899 100644 --- a/shared-lib/flowy-sync/src/client_folder/mod.rs +++ b/shared-lib/flowy-sync/src/client_folder/mod.rs @@ -1,12 +1,11 @@ -mod app_node; mod builder; mod folder_node; -mod folder_node_2; mod folder_pad; +mod trash_node; mod util; -mod view_node; mod workspace_node; -mod workspace_node_2; +pub use folder_node::*; pub use folder_node::*; pub use folder_pad::*; +pub use workspace_node::*; diff --git a/shared-lib/flowy-sync/src/client_folder/trash_node.rs b/shared-lib/flowy-sync/src/client_folder/trash_node.rs new file mode 100644 index 0000000000..0edda5cc1a --- /dev/null +++ b/shared-lib/flowy-sync/src/client_folder/trash_node.rs @@ -0,0 +1,20 @@ +use crate::client_folder::util::*; +use crate::client_folder::AtomicNodeTree; +use flowy_derive::Node; +use lib_ot::core::*; +use std::sync::Arc; + +#[derive(Clone, Node)] +#[node_type = "trash"] +pub struct TrashNode { + pub tree: Arc, + pub node_id: Option, + + #[node(get_value_with = "get_attributes_str_value")] + #[node(set_value_with = "set_attributes_str_value")] + pub id: String, + + #[node(get_value_with = "get_attributes_str_value")] + #[node(set_value_with = "set_attributes_str_value")] + pub name: String, +} diff --git a/shared-lib/flowy-sync/src/client_folder/util.rs b/shared-lib/flowy-sync/src/client_folder/util.rs index 42f09562b6..253c3962df 100644 --- a/shared-lib/flowy-sync/src/client_folder/util.rs +++ b/shared-lib/flowy-sync/src/client_folder/util.rs @@ -5,7 +5,7 @@ use std::sync::Arc; pub fn get_attributes_str_value(tree: Arc, node_id: &NodeId, key: &str) -> Option { tree.read() - .get_node(node_id.clone()) + .get_node(*node_id) .and_then(|node| node.attributes.get(key).cloned()) .and_then(|value| value.str_value()) } @@ -22,7 +22,7 @@ pub fn set_attributes_str_value( }; let mut new_attributes = old_attributes.clone(); new_attributes.insert(key, value); - let path = tree.read().path_from_node_id(node_id.clone()); + let path = tree.read().path_from_node_id(*node_id); let update_operation = NodeOperation::Update { path, changeset: Changeset::Attributes { @@ -34,21 +34,21 @@ pub fn set_attributes_str_value( Ok(()) } +#[allow(dead_code)] pub fn get_attributes_int_value(tree: Arc, node_id: &NodeId, key: &str) -> Option { tree.read() - .get_node(node_id.clone()) + .get_node(*node_id) .and_then(|node| node.attributes.get(key).cloned()) .and_then(|value| value.int_value()) } pub fn get_attributes(tree: Arc, node_id: &NodeId) -> Option { - tree.read() - .get_node(node_id.clone()) - .and_then(|node| Some(node.attributes.clone())) + tree.read().get_node(*node_id).map(|node| node.attributes.clone()) } +#[allow(dead_code)] pub fn get_attributes_value(tree: Arc, node_id: &NodeId, key: &str) -> Option { tree.read() - .get_node(node_id.clone()) + .get_node(*node_id) .and_then(|node| node.attributes.get(key).cloned()) } diff --git a/shared-lib/flowy-sync/src/client_folder/view_node.rs b/shared-lib/flowy-sync/src/client_folder/view_node.rs deleted file mode 100644 index a6af4a9d6d..0000000000 --- a/shared-lib/flowy-sync/src/client_folder/view_node.rs +++ /dev/null @@ -1,44 +0,0 @@ -use crate::client_folder::AtomicNodeTree; -use crate::errors::CollaborateResult; -use folder_rev_model::ViewRevision; -use lib_ot::core::{NodeDataBuilder, NodeOperation, Path, Transaction}; -use std::sync::Arc; - -#[derive(Debug, Clone)] -pub struct ViewNode { - tree: Arc, - path: Path, -} - -impl ViewNode { - pub(crate) fn from_view_revision( - transaction: &mut Transaction, - revision: ViewRevision, - tree: Arc, - path: Path, - ) -> CollaborateResult { - let view_node = NodeDataBuilder::new("view") - .insert_attribute("id", revision.id) - .insert_attribute("name", revision.name) - .build(); - - transaction.push_operation(NodeOperation::Insert { - path: path.clone(), - nodes: vec![view_node], - }); - - Ok(Self { tree, path }) - } - - fn get_id(&self) -> &str { - todo!() - } - - fn get_app_id(&self) -> &str { - todo!() - } - - fn set_app_id(&self, workspace_id: String) { - todo!() - } -} diff --git a/shared-lib/flowy-sync/src/client_folder/workspace_node.rs b/shared-lib/flowy-sync/src/client_folder/workspace_node.rs index 3f601f2ac1..abc752631a 100644 --- a/shared-lib/flowy-sync/src/client_folder/workspace_node.rs +++ b/shared-lib/flowy-sync/src/client_folder/workspace_node.rs @@ -1,104 +1,62 @@ -use crate::client_folder::app_node::AppNode; -use crate::client_folder::view_node::ViewNode; -use crate::client_folder::{get_attributes_str_value, get_attributes_value, set_attributes_str_value, AtomicNodeTree}; -use crate::errors::CollaborateResult; -use folder_rev_model::{AppRevision, WorkspaceRevision}; -use lib_ot::core::{AttributeValue, NodeDataBuilder, NodeOperation, Path, Transaction}; +use crate::client_folder::util::*; +use crate::client_folder::AtomicNodeTree; + +use flowy_derive::Node; +use lib_ot::core::*; use std::sync::Arc; -#[derive(Debug, Clone)] +#[derive(Clone, Node)] +#[node_type = "workspace"] pub struct WorkspaceNode { - pub(crate) id: String, - tree: Arc, - pub(crate) path: Path, - apps: Vec>, + pub tree: Arc, + pub node_id: Option, + + #[node(get_value_with = "get_attributes_str_value")] + #[node(set_value_with = "set_attributes_str_value")] + pub id: String, + + #[node(get_value_with = "get_attributes_str_value")] + #[node(set_value_with = "set_attributes_str_value")] + pub name: String, + + #[node(child_name = "app")] + pub apps: Vec, } impl WorkspaceNode { - pub(crate) fn from_workspace_revision( - transaction: &mut Transaction, - revision: WorkspaceRevision, - tree: Arc, - path: Path, - ) -> CollaborateResult { - let workspace_id = revision.id.clone(); - let workspace_node = NodeDataBuilder::new("workspace") - .insert_attribute("id", revision.id) - .insert_attribute("name", revision.name) - .build(); - - transaction.push_operation(NodeOperation::Insert { - path: path.clone(), - nodes: vec![workspace_node], - }); - - let apps = revision - .apps - .into_iter() - .enumerate() - .map(|(index, app)| (path.clone_with(index), app)) - .flat_map( - |(path, app)| match AppNode::from_app_revision(transaction, app, tree.clone(), path) { - Ok(app_node) => Some(Arc::new(app_node)), - Err(err) => { - tracing::warn!("Create app node failed: {:?}", err); - None - } - }, - ) - .collect::>>(); - - Ok(Self { - id: workspace_id, + pub fn new(tree: Arc, id: String, name: String) -> Self { + Self { tree, - path, - apps, - }) - } - - pub fn get_name(&self) -> Option { - get_attributes_str_value(self.tree.clone(), &self.path, "name") - } - - pub fn set_name(&self, name: &str) -> CollaborateResult<()> { - set_attributes_str_value(self.tree.clone(), &self.path, "name", name.to_string()) - } - - pub fn get_app(&self, app_id: &str) -> Option<&Arc> { - self.apps.iter().find(|app| app.id == app_id) - } - - pub fn get_mut_app(&mut self, app_id: &str) -> Option<&mut Arc> { - self.apps.iter_mut().find(|app| app.id == app_id) - } - - pub fn add_app(&mut self, app: AppRevision) -> CollaborateResult<()> { - let mut transaction = Transaction::new(); - let path = self.path.clone_with(self.apps.len()); - let app_node = AppNode::from_app_revision(&mut transaction, app, self.tree.clone(), path.clone())?; - let _ = self.tree.write().apply_transaction(transaction); - self.apps.push(Arc::new(app_node)); - Ok(()) - } - - pub fn remove_app(&mut self, app_id: &str) { - if let Some(index) = self.apps.iter().position(|app| app.id == app_id) { - let app = self.apps.remove(index); - let mut nodes = vec![]; - let app_node = self.tree.read().get_node_data_at_path(&app.path); - debug_assert!(app_node.is_some()); - if let Some(node_data) = app_node { - nodes.push(node_data); - } - let delete_operation = NodeOperation::Delete { - path: app.path.clone(), - nodes, - }; - let _ = self.tree.write().apply_op(delete_operation); + node_id: None, + id, + name, + apps: vec![], } } +} - pub fn get_all_apps(&self) -> Vec> { - self.apps.clone() +#[derive(Clone, Node)] +#[node_type = "app"] +pub struct AppNode { + pub tree: Arc, + pub node_id: Option, + + #[node(get_value_with = "get_attributes_str_value")] + #[node(set_value_with = "set_attributes_str_value")] + pub id: String, + + #[node(get_value_with = "get_attributes_str_value")] + #[node(set_value_with = "set_attributes_str_value")] + pub name: String, +} + +impl AppNode { + pub fn new(tree: Arc, id: String, name: String) -> Self { + Self { + tree, + node_id: None, + id, + name, + } } } diff --git a/shared-lib/flowy-sync/src/client_folder/workspace_node_2.rs b/shared-lib/flowy-sync/src/client_folder/workspace_node_2.rs deleted file mode 100644 index 223ea6e90e..0000000000 --- a/shared-lib/flowy-sync/src/client_folder/workspace_node_2.rs +++ /dev/null @@ -1,43 +0,0 @@ -use crate::client_folder::util::*; -use crate::client_folder::AtomicNodeTree; -use crate::errors::CollaborateResult; -use flowy_derive::Node; -use lib_ot::core::*; -use std::sync::Arc; - -#[derive(Clone, Node)] -#[node_type = "workspace"] -pub struct WorkspaceNode2 { - tree: Arc, - node_id: NodeId, - - #[node(get_value_with = "get_attributes_str_value")] - #[node(set_value_with = "set_attributes_str_value")] - pub id: String, - - #[node(get_value_with = "get_attributes_str_value")] - #[node(set_value_with = "set_attributes_str_value")] - #[node(rename = "name123")] - pub name: String, - - #[node(get_value_with = "get_attributes_int_value")] - pub time: i64, - - #[node(child_name = "app")] - pub apps: Vec, -} - -#[derive(Clone, Node)] -#[node_type = "app"] -pub struct AppNode2 { - tree: Arc, - node_id: NodeId, - - #[node(get_value_with = "get_attributes_str_value")] - #[node(set_value_with = "set_attributes_str_value")] - pub id: String, - - #[node(get_value_with = "get_attributes_str_value")] - #[node(set_value_with = "set_attributes_str_value")] - pub name: String, -} diff --git a/shared-lib/flowy-sync/tests/client_folder/folder_test.rs b/shared-lib/flowy-sync/tests/client_folder/folder_test.rs index e8f5410071..90ce6b7c5f 100644 --- a/shared-lib/flowy-sync/tests/client_folder/folder_test.rs +++ b/shared-lib/flowy-sync/tests/client_folder/folder_test.rs @@ -1,9 +1,8 @@ -use flowy_sync::client_folder::FolderNodePad; -use folder_rev_model::WorkspaceRevision; +use flowy_sync::client_folder::{FolderNodePad, WorkspaceNode}; #[test] fn client_folder_create_default_folder_test() { - let folder_pad = FolderNodePad::default(); + let folder_pad = FolderNodePad::new(); let json = folder_pad.to_json(false).unwrap(); assert_eq!( json, @@ -13,16 +12,9 @@ fn client_folder_create_default_folder_test() { #[test] fn client_folder_create_default_folder_with_workspace_test() { - let mut folder_pad = FolderNodePad::default(); - let workspace = WorkspaceRevision { - id: "1".to_string(), - name: "workspace name".to_string(), - desc: "".to_string(), - apps: vec![], - modified_time: 0, - create_time: 0, - }; - folder_pad.add_workspace(workspace).unwrap(); + let mut folder_pad = FolderNodePad::new(); + let workspace = WorkspaceNode::new(folder_pad.tree.clone(), "1".to_string(), "workspace name".to_string()); + folder_pad.workspaces.add_workspace(workspace).unwrap(); let json = folder_pad.to_json(false).unwrap(); assert_eq!( json, @@ -37,17 +29,10 @@ fn client_folder_create_default_folder_with_workspace_test() { #[test] fn client_folder_delete_workspace_test() { - let mut folder_pad = FolderNodePad::default(); - let workspace = WorkspaceRevision { - id: "1".to_string(), - name: "workspace name".to_string(), - desc: "".to_string(), - apps: vec![], - modified_time: 0, - create_time: 0, - }; - folder_pad.add_workspace(workspace).unwrap(); - folder_pad.remove_workspace("1"); + let mut folder_pad = FolderNodePad::new(); + let workspace = WorkspaceNode::new(folder_pad.tree.clone(), "1".to_string(), "workspace name".to_string()); + folder_pad.workspaces.add_workspace(workspace).unwrap(); + folder_pad.workspaces.remove_workspace("1"); let json = folder_pad.to_json(false).unwrap(); assert_eq!( json, @@ -57,23 +42,17 @@ fn client_folder_delete_workspace_test() { #[test] fn client_folder_update_workspace_name_test() { - let mut folder_pad = FolderNodePad::default(); - let workspace = WorkspaceRevision { - id: "1".to_string(), - name: "workspace name".to_string(), - desc: "".to_string(), - apps: vec![], - modified_time: 0, - create_time: 0, - }; - folder_pad.add_workspace(workspace).unwrap(); + let mut folder_pad = FolderNodePad::new(); + let workspace = WorkspaceNode::new(folder_pad.tree.clone(), "1".to_string(), "workspace name".to_string()); + folder_pad.workspaces.add_workspace(workspace).unwrap(); folder_pad - .get_workspace("1") + .workspaces + .get_mut_workspace("1") .unwrap() - .set_name("My first workspace") - .unwrap(); + .set_name("my first workspace".to_string()); + assert_eq!( - folder_pad.get_workspace("1").unwrap().get_name().unwrap(), - "My first workspace" + folder_pad.workspaces.get_workspace("1").unwrap().get_name().unwrap(), + "my first workspace" ); } diff --git a/shared-lib/flowy-sync/tests/client_folder/script.rs b/shared-lib/flowy-sync/tests/client_folder/script.rs index d5f6beda95..2200e37a58 100644 --- a/shared-lib/flowy-sync/tests/client_folder/script.rs +++ b/shared-lib/flowy-sync/tests/client_folder/script.rs @@ -1,14 +1,18 @@ -use flowy_sync::client_folder::FolderNodePad; -use folder_rev_model::{AppRevision, WorkspaceRevision}; -use std::sync::Arc; +use flowy_sync::client_folder::{AppNode, FolderNodePad, WorkspaceNode}; +use folder_rev_model::AppRevision; +use lib_ot::core::Path; pub enum FolderNodePadScript { + CreateWorkspace { id: String, name: String }, + DeleteWorkspace { id: String }, + AssertPathOfWorkspace { id: String, expected_path: Path }, + AssertNumberOfWorkspace { expected: usize }, CreateApp { id: String, name: String }, DeleteApp { id: String }, UpdateApp { id: String, name: String }, AssertApp { id: String, expected: Option }, AssertAppContent { id: String, name: String }, - AssertNumberOfApps { expected: usize }, + // AssertNumberOfApps { expected: usize }, } pub struct FolderNodePadTest { @@ -18,15 +22,8 @@ pub struct FolderNodePadTest { impl FolderNodePadTest { pub fn new() -> FolderNodePadTest { let mut folder_pad = FolderNodePad::default(); - let workspace = WorkspaceRevision { - id: "1".to_string(), - name: "workspace name".to_string(), - desc: "".to_string(), - apps: vec![], - modified_time: 0, - create_time: 0, - }; - let _ = folder_pad.add_workspace(workspace).unwrap(); + let workspace = WorkspaceNode::new(folder_pad.tree.clone(), "1".to_string(), "workspace name".to_string()); + let _ = folder_pad.workspaces.add_workspace(workspace).unwrap(); Self { folder_pad } } @@ -38,32 +35,34 @@ impl FolderNodePadTest { pub fn run_script(&mut self, script: FolderNodePadScript) { match script { + FolderNodePadScript::CreateWorkspace { id, name } => { + let workspace = WorkspaceNode::new(self.folder_pad.tree.clone(), id, name); + self.folder_pad.workspaces.add_workspace(workspace).unwrap(); + } + FolderNodePadScript::DeleteWorkspace { id } => { + self.folder_pad.workspaces.remove_workspace(id); + } + FolderNodePadScript::AssertPathOfWorkspace { id, expected_path } => { + let workspace_node: &WorkspaceNode = self.folder_pad.workspaces.get_workspace(id).unwrap(); + let node_id = workspace_node.node_id.unwrap(); + let path = self.folder_pad.tree.read().path_from_node_id(node_id); + assert_eq!(path, expected_path); + } + FolderNodePadScript::AssertNumberOfWorkspace { expected } => { + assert_eq!(self.folder_pad.workspaces.len(), expected); + } FolderNodePadScript::CreateApp { id, name } => { - let revision = AppRevision { - id, - workspace_id: "1".to_string(), - name, - desc: "".to_string(), - belongings: vec![], - version: 0, - modified_time: 0, - create_time: 0, - }; - + let app_node = AppNode::new(self.folder_pad.tree.clone(), id, name); let workspace_node = self.folder_pad.get_mut_workspace("1").unwrap(); - let workspace_node = Arc::make_mut(workspace_node); - let _ = workspace_node.add_app(revision).unwrap(); + let _ = workspace_node.add_app(app_node).unwrap(); } FolderNodePadScript::DeleteApp { id } => { let workspace_node = self.folder_pad.get_mut_workspace("1").unwrap(); - let workspace_node = Arc::make_mut(workspace_node); workspace_node.remove_app(&id); } FolderNodePadScript::UpdateApp { id, name } => { let workspace_node = self.folder_pad.get_mut_workspace("1").unwrap(); - let workspace_node = Arc::make_mut(workspace_node); - let app_node = Arc::make_mut(workspace_node.get_mut_app(&id).unwrap()); - app_node.set_name(name).unwrap(); + workspace_node.get_mut_app(&id).unwrap().set_name(name); } FolderNodePadScript::AssertApp { id, expected } => { let workspace_node = self.folder_pad.get_workspace("1").unwrap(); @@ -73,7 +72,7 @@ impl FolderNodePadTest { Some(expected_app) => { let app_node = app.unwrap(); assert_eq!(expected_app.name, app_node.get_name().unwrap()); - assert_eq!(expected_app.id, app_node.id); + assert_eq!(expected_app.id, app_node.get_id().unwrap()); } } } @@ -81,11 +80,10 @@ impl FolderNodePadTest { let workspace_node = self.folder_pad.get_workspace("1").unwrap(); let app = workspace_node.get_app(&id).unwrap(); assert_eq!(app.get_name().unwrap(), name) - } - FolderNodePadScript::AssertNumberOfApps { expected } => { - let workspace_node = self.folder_pad.get_workspace("1").unwrap(); - assert_eq!(workspace_node.get_all_apps().len(), expected); - } + } // FolderNodePadScript::AssertNumberOfApps { expected } => { + // let workspace_node = self.folder_pad.get_workspace("1").unwrap(); + // assert_eq!(workspace_node.apps.len(), expected); + // } } } } diff --git a/shared-lib/flowy-sync/tests/client_folder/workspace_test.rs b/shared-lib/flowy-sync/tests/client_folder/workspace_test.rs index 3211a050e1..1208fcc1ca 100644 --- a/shared-lib/flowy-sync/tests/client_folder/workspace_test.rs +++ b/shared-lib/flowy-sync/tests/client_folder/workspace_test.rs @@ -1,6 +1,39 @@ use crate::client_folder::script::FolderNodePadScript::*; use crate::client_folder::script::FolderNodePadTest; -use flowy_sync::client_folder::FolderNodePad; + +#[test] +fn client_folder_create_multi_workspaces_test() { + let mut test = FolderNodePadTest::new(); + test.run_scripts(vec![ + AssertPathOfWorkspace { + id: "1".to_string(), + expected_path: vec![0, 0, 0].into(), + }, + CreateWorkspace { + id: "a".to_string(), + name: "workspace a".to_string(), + }, + AssertPathOfWorkspace { + id: "a".to_string(), + expected_path: vec![0, 0, 1].into(), + }, + CreateWorkspace { + id: "b".to_string(), + name: "workspace b".to_string(), + }, + AssertPathOfWorkspace { + id: "b".to_string(), + expected_path: vec![0, 0, 2].into(), + }, + AssertNumberOfWorkspace { expected: 3 }, + // The path of the workspace 'b' will be changed after deleting the 'a' workspace. + DeleteWorkspace { id: "a".to_string() }, + AssertPathOfWorkspace { + id: "b".to_string(), + expected_path: vec![0, 0, 1].into(), + }, + ]); +} #[test] fn client_folder_create_app_test() { diff --git a/shared-lib/grid-rev-model/src/grid_setting_rev.rs b/shared-lib/grid-rev-model/src/grid_setting_rev.rs index 785df6cc52..305144f938 100644 --- a/shared-lib/grid-rev-model/src/grid_setting_rev.rs +++ b/shared-lib/grid-rev-model/src/grid_setting_rev.rs @@ -61,8 +61,8 @@ where predicate: impl Fn(&Arc) -> bool, ) -> Option> { let objects = self.get_objects(field_id, field_type)?; - let index = objects.iter().position(|object| predicate(object))?; - objects.get(index).map(|object| object.clone()) + let index = objects.iter().position(predicate)?; + objects.get(index).cloned() } pub fn get_mut_object( @@ -72,7 +72,7 @@ where predicate: impl Fn(&Arc) -> bool, ) -> Option<&mut Arc> { let objects = self.get_mut_objects(field_id, field_type)?; - let index = objects.iter().position(|object| predicate(object))?; + let index = objects.iter().position(predicate)?; objects.get_mut(index) } diff --git a/shared-lib/lib-ot/src/core/node_tree/tree.rs b/shared-lib/lib-ot/src/core/node_tree/tree.rs index 0cd90e4b55..050160c7e9 100644 --- a/shared-lib/lib-ot/src/core/node_tree/tree.rs +++ b/shared-lib/lib-ot/src/core/node_tree/tree.rs @@ -196,7 +196,7 @@ impl NodeTree { path.push(counter); current_node = parent_node; } - + path.reverse(); Path(path) }