diff --git a/shared-lib/flowy-ast/src/ast.rs b/shared-lib/flowy-ast/src/ast.rs index 4986e0a663..44616cb15e 100644 --- a/shared-lib/flowy-ast/src/ast.rs +++ b/shared-lib/flowy-ast/src/ast.rs @@ -123,7 +123,9 @@ pub struct ASTField<'a> { pub node_attrs: NodeStructAttrs, pub ty: &'a syn::Type, pub original: &'a syn::Field, + // If the field is Vec, then the bracket_ty will be Vec pub bracket_ty: Option, + // If the field is Vec, then the bracket_inner_ty will be String pub bracket_inner_ty: Option, pub bracket_category: Option, } diff --git a/shared-lib/flowy-ast/src/node_attrs.rs b/shared-lib/flowy-ast/src/node_attrs.rs index 26c11cffc6..3c14c0a426 100644 --- a/shared-lib/flowy-ast/src/node_attrs.rs +++ b/shared-lib/flowy-ast/src/node_attrs.rs @@ -11,8 +11,9 @@ use syn::{ pub struct NodeStructAttrs { pub rename: Option, - pub is_children: bool, - node_index: Option, + pub has_child: bool, + pub child_name: Option, + pub child_index: Option, get_node_value_with: Option, set_node_value_with: Option, } @@ -20,9 +21,9 @@ pub struct NodeStructAttrs { impl NodeStructAttrs { /// Extract out the `#[node(...)]` attributes from a struct field. pub fn from_ast(ast_result: &ASTResult, index: usize, field: &syn::Field) -> Self { - let mut node_index = ASTAttr::none(ast_result, NODE_INDEX); - let mut rename = ASTAttr::none(ast_result, NODE_RENAME); - let mut is_children = ASTAttr::none(ast_result, NODE_CHILDREN); + 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); @@ -33,25 +34,27 @@ impl NodeStructAttrs { .flatten() { match &meta_item { - // Parse '#[node(index = x)]' - Meta(NameValue(m)) if m.path == NODE_INDEX => { - if let syn::Lit::Int(lit) = &m.lit { - node_index.set(&m.path, lit.clone()); - } - } - - // Parse '#[node(children)]' - Meta(Path(path)) if path == NODE_CHILDREN => { - eprintln!("😄 {:?}", path); - is_children.set(path, true); - } - // Parse '#[node(rename = x)]' - Meta(NameValue(m)) if m.path == NODE_RENAME => { + Meta(NameValue(m)) if m.path == RENAME_NODE => { if let syn::Lit::Str(lit) = &m.lit { rename.set(&m.path, lit.clone()); } } + + // Parse '#[node(child_name = x)]' + Meta(NameValue(m)) if m.path == CHILD_NODE_NAME => { + if let syn::Lit::Str(lit) = &m.lit { + child_name.set(&m.path, lit.clone()); + } + } + + // Parse '#[node(child_index = x)]' + Meta(NameValue(m)) if m.path == CHILD_NODE_INDEX => { + if let syn::Lit::Int(lit) = &m.lit { + child_index.set(&m.path, lit.clone()); + } + } + // Parse `#[node(get_node_value_with = "...")]` Meta(NameValue(m)) if m.path == GET_NODE_VALUE_WITH => { if let Ok(path) = parse_lit_into_expr_path(ast_result, GET_NODE_VALUE_WITH, &m.lit) { @@ -76,11 +79,12 @@ impl NodeStructAttrs { } } } - + let child_name = child_name.get(); NodeStructAttrs { rename: rename.get(), - node_index: node_index.get(), - is_children: is_children.get().unwrap_or(false), + child_index: child_index.get(), + has_child: child_name.is_some(), + child_name, get_node_value_with: get_node_value_with.get(), set_node_value_with: set_node_value_with.get(), } diff --git a/shared-lib/flowy-ast/src/symbol.rs b/shared-lib/flowy-ast/src/symbol.rs index 51a6e06aca..c3455a1e4b 100644 --- a/shared-lib/flowy-ast/src/symbol.rs +++ b/shared-lib/flowy-ast/src/symbol.rs @@ -37,8 +37,9 @@ pub const NODE_ATTRS: Symbol = Symbol("node"); pub const NODES_ATTRS: Symbol = Symbol("nodes"); pub const NODE_TYPE: Symbol = Symbol("node_type"); pub const NODE_INDEX: Symbol = Symbol("index"); -pub const NODE_RENAME: Symbol = Symbol("rename"); -pub const NODE_CHILDREN: Symbol = Symbol("children"); +pub const RENAME_NODE: Symbol = Symbol("rename"); +pub const CHILD_NODE_NAME: Symbol = Symbol("child_name"); +pub const CHILD_NODE_INDEX: Symbol = Symbol("child_index"); pub const SKIP_NODE_ATTRS: Symbol = Symbol("skip_node_attribute"); pub const GET_NODE_VALUE_WITH: Symbol = Symbol("get_value_with"); pub const SET_NODE_VALUE_WITH: Symbol = Symbol("set_value_with"); diff --git a/shared-lib/flowy-derive/src/node/mod.rs b/shared-lib/flowy-derive/src/node/mod.rs index 10738b255c..0ea8cc0191 100644 --- a/shared-lib/flowy-derive/src/node/mod.rs +++ b/shared-lib/flowy-derive/src/node/mod.rs @@ -9,18 +9,98 @@ pub fn expand_derive(input: &syn::DeriveInput) -> Result TokenStream { +pub fn make_helper_funcs_token_stream(ast: &ASTContainer) -> TokenStream { let mut token_streams = TokenStream::default(); + 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()) + } + } + }); + token_streams +} + +pub fn make_alter_children_token_stream(ast_result: &ASTResult, ast: &ASTContainer) -> TokenStream { + let mut token_streams = TokenStream::default(); + let children_fields = ast + .data + .all_fields() + .filter(|field| field.node_attrs.has_child) + .collect::>(); + + if !children_fields.is_empty() { + let struct_ident = &ast.ident; + if children_fields.len() > 1 { + ast_result.error_spanned_by(struct_ident, "Only one children property"); + return token_streams; + } + 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()); + let add_func_name = format_ident!("add_{}", child_name.value()); + let remove_func_name = format_ident!("remove_{}", child_name.value()); + let ty = children_field.bracket_inner_ty.as_ref().unwrap().clone(); + + 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_mut_func_name(&mut self, id: &str) -> Option<&mut #ty> { + 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) { + let element = self.#field_name.remove(index); + let element_path = element.get_path(); + + 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()) { + nodes.push(node_data); + } + let _ = write_guard.apply_op(NodeOperation::Delete { + path: element_path, + nodes, + }); + } + } + + pub fn #add_func_name(&mut self, value: #ty) { + let mut transaction = Transaction::new(); + let parent_path = self.get_path(); + let path = parent_path.clone_with(self.#field_name.len()); + let node_data = value.to_node_data(); + transaction.push_operation(NodeOperation::Insert { + path, + nodes: vec![node_data], + }); + + let _ = self.tree.write().apply_transaction(transaction); + self.#field_name.push(value); + } + } + }); + } token_streams } @@ -35,7 +115,7 @@ pub fn make_to_node_data_token_stream(ast: &ASTContainer) -> TokenStream { let set_key_values = ast .data .all_fields() - .filter(|field| !field.node_attrs.is_children) + .filter(|field| !field.node_attrs.has_child) .flat_map(|field| { let mut field_name = field.name().expect("the name of the field should not be empty"); let original_field_name = field.name().expect("the name of the field should not be empty"); @@ -51,7 +131,7 @@ pub fn make_to_node_data_token_stream(ast: &ASTContainer) -> TokenStream { let children_fields = ast .data .all_fields() - .filter(|field| field.node_attrs.is_children) + .filter(|field| field.node_attrs.has_child) .collect::>(); let childrens_token_streams = match children_fields.is_empty() { @@ -72,8 +152,8 @@ pub fn make_to_node_data_token_stream(ast: &ASTContainer) -> TokenStream { }; token_streams.extend(quote! { - impl #struct_ident { - pub fn to_node_data(&self) -> NodeData { + impl ToNodeData for #struct_ident { + fn to_node_data(&self) -> NodeData { #childrens_token_streams let builder = NodeDataBuilder::new(#node_type) @@ -94,7 +174,7 @@ pub fn make_get_set_value_token_steam(ast: &ASTContainer) -> Option let tree = format_ident!("tree"); for field in ast.data.all_fields() { - if field.node_attrs.is_children { + if field.node_attrs.has_child { continue; } @@ -113,7 +193,7 @@ pub fn make_get_set_value_token_steam(ast: &ASTContainer) -> Option 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.path, #field_name_str) + #get_value_with_fn(self.#tree.clone(), &self.node_id, #field_name_str) } } }); @@ -123,12 +203,11 @@ pub fn make_get_set_value_token_steam(ast: &ASTContainer) -> Option 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.path, #field_name_str, value); + let _ = #set_value_with_fn(self.#tree.clone(), &self.node_id, #field_name_str, value); } } }); } } - ast.data.all_fields().for_each(|field| {}); Some(token_streams) } 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 58cde82a17..e9541236be 100644 --- a/shared-lib/flowy-sync/src/client_folder/folder_node.rs +++ b/shared-lib/flowy-sync/src/client_folder/folder_node.rs @@ -11,42 +11,6 @@ use std::sync::Arc; pub type AtomicNodeTree = RwLock; -// pub struct FolderNodePad2 { -// tree: Arc, -// -// #[node(rename = "workspaces", revision = "WorkspaceRevision")] -// workspaces: Vec>, -// } -// -// impl FolderNodePad2 { -// pub fn get_workspace() {} -// pub fn get_mut_workspace() {} -// pub fn add_workspace() {} -// pub fn remove_workspace() {} -// pub fn to_json() {} -// } -// -// #[derive(Debug, Clone)] -// pub struct WorkspaceNode2 { -// tree: Arc, -// pub id: String, -// pub name: String, -// pub path: Path, -// } -// -// impl WorkspaceNode2 { -// pub fn get_id() {} -// pub fn set_id() {} -// pub fn get_name() {} -// pub fn set_name() {} -// pub fn get_apps() {} -// -// pub fn get_app() {} -// pub fn get_mut_app() {} -// pub fn add_app() {} -// pub fn remove_app() {} -// } - pub struct FolderNodePad { tree: Arc, // name: workspaces, index of the node, @@ -71,31 +35,29 @@ impl FolderNodePad { 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![]; - let workspace_node = self.tree.read().get_node_data_at_path(&workspace.path); - debug_assert!(workspace_node.is_some()); - if let Some(node_data) = workspace_node { + if let Some(node_data) = write_guard.get_node_data_at_path(&workspace.path) { nodes.push(node_data); } - let delete_operation = NodeOperation::Delete { + let _ = write_guard.apply_op(NodeOperation::Delete { path: workspace.path.clone(), nodes, - }; - let _ = self.tree.write().apply_op(delete_operation); + }); } } pub fn add_workspace(&mut self, revision: WorkspaceRevision) -> CollaborateResult<()> { let mut transaction = Transaction::new(); - let workspace_node = WorkspaceNode::from_workspace_revision( + 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(workspace_node)); + self.workspaces.push(Arc::new(node)); Ok(()) } 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 new file mode 100644 index 0000000000..19d41a0ffb --- /dev/null +++ b/shared-lib/flowy-sync/src/client_folder/folder_node_2.rs @@ -0,0 +1,51 @@ +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 fa0dde1ce9..ba42b98317 100644 --- a/shared-lib/flowy-sync/src/client_folder/mod.rs +++ b/shared-lib/flowy-sync/src/client_folder/mod.rs @@ -1,7 +1,9 @@ mod app_node; mod builder; mod folder_node; +mod folder_node_2; mod folder_pad; +mod util; mod view_node; mod workspace_node; mod workspace_node_2; diff --git a/shared-lib/flowy-sync/src/client_folder/util.rs b/shared-lib/flowy-sync/src/client_folder/util.rs new file mode 100644 index 0000000000..42f09562b6 --- /dev/null +++ b/shared-lib/flowy-sync/src/client_folder/util.rs @@ -0,0 +1,54 @@ +use crate::client_folder::AtomicNodeTree; +use crate::errors::CollaborateResult; +use lib_ot::core::{AttributeHashMap, AttributeValue, Changeset, NodeId, NodeOperation}; +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()) + .and_then(|node| node.attributes.get(key).cloned()) + .and_then(|value| value.str_value()) +} + +pub fn set_attributes_str_value( + tree: Arc, + node_id: &NodeId, + key: &str, + value: String, +) -> CollaborateResult<()> { + let old_attributes = match get_attributes(tree.clone(), node_id) { + None => AttributeHashMap::new(), + Some(attributes) => attributes, + }; + let mut new_attributes = old_attributes.clone(); + new_attributes.insert(key, value); + let path = tree.read().path_from_node_id(node_id.clone()); + let update_operation = NodeOperation::Update { + path, + changeset: Changeset::Attributes { + new: new_attributes, + old: old_attributes, + }, + }; + let _ = tree.write().apply_op(update_operation)?; + Ok(()) +} + +pub fn get_attributes_int_value(tree: Arc, node_id: &NodeId, key: &str) -> Option { + tree.read() + .get_node(node_id.clone()) + .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())) +} + +pub fn get_attributes_value(tree: Arc, node_id: &NodeId, key: &str) -> Option { + tree.read() + .get_node(node_id.clone()) + .and_then(|node| node.attributes.get(key).cloned()) +} 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 index 47901daee3..223ea6e90e 100644 --- a/shared-lib/flowy-sync/src/client_folder/workspace_node_2.rs +++ b/shared-lib/flowy-sync/src/client_folder/workspace_node_2.rs @@ -1,3 +1,4 @@ +use crate::client_folder::util::*; use crate::client_folder::AtomicNodeTree; use crate::errors::CollaborateResult; use flowy_derive::Node; @@ -8,7 +9,7 @@ use std::sync::Arc; #[node_type = "workspace"] pub struct WorkspaceNode2 { tree: Arc, - path: Path, + node_id: NodeId, #[node(get_value_with = "get_attributes_str_value")] #[node(set_value_with = "set_attributes_str_value")] @@ -22,7 +23,7 @@ pub struct WorkspaceNode2 { #[node(get_value_with = "get_attributes_int_value")] pub time: i64, - #[node(children)] + #[node(child_name = "app")] pub apps: Vec, } @@ -30,7 +31,7 @@ pub struct WorkspaceNode2 { #[node_type = "app"] pub struct AppNode2 { tree: Arc, - path: Path, + node_id: NodeId, #[node(get_value_with = "get_attributes_str_value")] #[node(set_value_with = "set_attributes_str_value")] @@ -40,53 +41,3 @@ pub struct AppNode2 { #[node(set_value_with = "set_attributes_str_value")] pub name: String, } - -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(()) -} - -pub fn get_attributes_int_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.int_value()) -} - -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()) -} diff --git a/shared-lib/lib-ot/src/core/node_tree/node.rs b/shared-lib/lib-ot/src/core/node_tree/node.rs index 67fdbd3110..aae7ac97bc 100644 --- a/shared-lib/lib-ot/src/core/node_tree/node.rs +++ b/shared-lib/lib-ot/src/core/node_tree/node.rs @@ -10,6 +10,15 @@ pub trait ToNodeData: Send + Sync { fn to_node_data(&self) -> NodeData; } +impl ToNodeData for Box +where + T: ToNodeData, +{ + fn to_node_data(&self) -> NodeData { + (**self).to_node_data() + } +} + #[derive(Default, Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] pub struct NodeData { #[serde(rename = "type")]