diff --git a/Cargo.toml b/Cargo.toml index acfe318..e4fd75f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ repository = "https://github.com/dashpay/grovedbg" eframe = { version = "0.29.1", features = ["persistence"] } egui_logger = { git = "https://github.com/fominok/egui_logger", rev = "8024354acc26678b31d933c2cf7e94498989634f" } futures = "0.3.30" -grovedbg-types = { path = "../grovedb/grovedbg-types", version = "2.0.3" } +grovedbg-types = { path = "../grovedb/grovedbg-types", version = "3.0.0" } hex = "0.4.3" integer-encoding = "4.0.2" log = "0.4.22" @@ -25,7 +25,7 @@ serde_json = "1.0.128" reingold-tilford = "1.0.0" anyhow = "1.0.89" chrono = "0.4.38" -dpp = { git = "https://github.com/dashpay/platform", version = "1.4.0-dev.2", default-features = false, features = ["vote-serde-conversion"] } +dpp = { git = "https://github.com/dashpay/platform", branch = "v2.0-dev", default-features = false, features = ["vote-serde-conversion", "state-transitions"] } egui_json_tree = { git = "https://github.com/bircni/egui_json_tree", rev = "a3f8d4954d11cb60a846f8bcbfe848648f28af93" } grovedb-epoch-based-storage-flags = "2.0.3" diff --git a/README.md b/README.md index e25e84e..c79478d 100644 --- a/README.md +++ b/README.md @@ -405,3 +405,9 @@ Display** dropdown. Profile entries are recursive, allowing you to match child subtrees of already matched elements, and continue further down the hierarchy. This enables you to create a path to a specific subtree using **Key** entries, or apply changes to multiple nested subtrees more broadly by using **Capture** when appropriate. + +## Building for web + +``` +RUSTFLAGS='--cfg=web_sys_unstable_apis' cargo watch -- trunk build --release +``` diff --git a/src/profiles.rs b/src/profiles.rs index 8f385d2..814af1e 100644 --- a/src/profiles.rs +++ b/src/profiles.rs @@ -331,28 +331,108 @@ fn drive_profile() -> Profile { collapsed: true, alias: "Votes".to_string(), value_display: None, - sub_items: vec![ProfileEntry { - key: vec![101].into(), - collapsed: true, - alias: "Voting end dates".to_owned(), - value_display: None, - sub_items: vec![ProfileEntry { - key: ProfileEntryKey::Capture, - alias: "{}".to_owned(), + sub_items: vec![ + ProfileEntry { + key: vec![101].into(), + collapsed: true, + alias: "End date queries".to_owned(), + value_display: None, sub_items: vec![ProfileEntry { key: ProfileEntryKey::Capture, alias: "{}".to_owned(), - sub_items: Vec::default(), - display: BytesDisplayVariant::U8, + sub_items: vec![ProfileEntry { + key: ProfileEntryKey::Capture, + alias: "{}".to_owned(), + sub_items: Vec::default(), + display: BytesDisplayVariant::U8, + collapsed: true, + value_display: Some(BytesDisplayVariant::DppVotePoll), + }], + value_display: None, + display: BytesDisplayVariant::DriveTimestamp, collapsed: true, - value_display: Some(BytesDisplayVariant::DppVotePoll), }], + display: BytesDisplayVariant::U8, + }, + ProfileEntry { + key: vec![100].into(), + collapsed: true, + alias: "Decisions".to_owned(), value_display: None, - display: BytesDisplayVariant::DriveTimestamp, + sub_items: vec![ProfileEntry { + key: ProfileEntryKey::Capture, + alias: "{}".to_owned(), + sub_items: vec![], + value_display: None, + display: BytesDisplayVariant::DriveTimestamp, + collapsed: true, + }], + display: BytesDisplayVariant::U8, + }, + ProfileEntry { + key: vec![99].into(), collapsed: true, - }], - display: BytesDisplayVariant::U8, - }], + alias: "Contested Resource".to_owned(), + value_display: None, + sub_items: vec![ + ProfileEntry { + key: vec![112].into(), + alias: "Active Polls".to_owned(), + sub_items: vec![ProfileEntry { + key: ProfileEntryKey::Capture, + alias: "Contract id: {}".to_owned(), + sub_items: vec![ProfileEntry { + key: ProfileEntryKey::Capture, + alias: "Document type name: {}".to_owned(), + sub_items: vec![ + ProfileEntry { + key: vec![0].into(), + alias: "Contested document storage".to_owned(), + sub_items: vec![], + display: BytesDisplayVariant::U8, + collapsed: true, + value_display: None, + }, + ProfileEntry { + key: vec![1].into(), + alias: "Contested document indexes".to_owned(), + sub_items: vec![], + display: BytesDisplayVariant::U8, + collapsed: true, + value_display: None, + }, + ], + display: BytesDisplayVariant::String, + collapsed: true, + value_display: None, + }], + display: BytesDisplayVariant::Hex, + collapsed: true, + value_display: None, + }], + value_display: None, + display: BytesDisplayVariant::Hex, + collapsed: true, + }, + ProfileEntry { + key: vec![105].into(), + alias: "Identifier Votes Query".to_owned(), + sub_items: vec![ProfileEntry { + key: ProfileEntryKey::Capture, + alias: "Identity id: {}".to_owned(), + sub_items: vec![], + display: BytesDisplayVariant::Hex, + collapsed: true, + value_display: None, + }], + value_display: None, + display: BytesDisplayVariant::U8, + collapsed: true, + }, + ], + display: BytesDisplayVariant::U8, + }, + ], display: BytesDisplayVariant::U8, }, ], diff --git a/src/proof_viewer.rs b/src/proof_viewer.rs index 7e2fc79..e18d106 100644 --- a/src/proof_viewer.rs +++ b/src/proof_viewer.rs @@ -270,8 +270,17 @@ impl MerkProofNodeViewer { }); match ft { grovedbg_types::TreeFeatureType::BasicMerkNode => ui.label("Basic merk node"), - grovedbg_types::TreeFeatureType::SummedMerkNode(x) => { - ui.label(format!("Summed merk node: {x}")) + grovedbg_types::TreeFeatureType::SummedMerkNode(sum) => { + ui.label(format!("Summed merk node: {sum}")) + } + grovedbg_types::TreeFeatureType::BigSummedMerkNode(sum) => { + ui.label(format!("Big summed merk node: {sum}")) + } + grovedbg_types::TreeFeatureType::CountedMerkNode(count) => { + ui.label(format!("Counted merk node: {count}")) + } + grovedbg_types::TreeFeatureType::CountedSummedMerkNode(count, sum) => { + ui.label(format!("Counted/Summed merk node: count {count} sum {sum}")) } }; } @@ -316,6 +325,152 @@ impl ProveOptionsView { } } +pub(crate) enum ReferencePath { + AbsolutePathReference { + path: Vec, + }, + UpstreamRootHeightReference { + n_keep: u32, + path_append: Vec, + }, + UpstreamRootHeightWithParentPathAdditionReference { + n_keep: u32, + path_append: Vec, + }, + UpstreamFromElementHeightReference { + n_remove: u32, + path_append: Vec, + }, + CousinReference { + swap_parent: BytesView, + }, + RemovedCousinReference { + swap_parent: Vec, + }, + SiblingReference { + sibling_key: BytesView, + }, +} + +impl From for ReferencePath { + fn from(value: grovedbg_types::ReferencePath) -> Self { + match value { + grovedbg_types::ReferencePath::AbsolutePathReference { path, .. } => { + Self::AbsolutePathReference { + path: path.into_iter().map(|s| BytesView::new(s)).collect(), + } + } + + grovedbg_types::ReferencePath::UpstreamRootHeightReference { + n_keep, path_append, .. + } => Self::UpstreamRootHeightReference { + n_keep, + path_append: path_append.into_iter().map(|s| BytesView::new(s)).collect(), + }, + + grovedbg_types::ReferencePath::UpstreamRootHeightWithParentPathAdditionReference { + n_keep, + path_append, + .. + } => Self::UpstreamRootHeightWithParentPathAdditionReference { + n_keep, + path_append: path_append.into_iter().map(|s| BytesView::new(s)).collect(), + }, + + grovedbg_types::ReferencePath::UpstreamFromElementHeightReference { + n_remove, + path_append, + .. + } => Self::UpstreamFromElementHeightReference { + n_remove, + path_append: path_append.into_iter().map(|s| BytesView::new(s)).collect(), + }, + grovedbg_types::ReferencePath::CousinReference { swap_parent, .. } => Self::CousinReference { + swap_parent: BytesView::new(swap_parent), + }, + grovedbg_types::ReferencePath::RemovedCousinReference { swap_parent, .. } => { + Self::RemovedCousinReference { + swap_parent: swap_parent.into_iter().map(|s| BytesView::new(s)).collect(), + } + } + grovedbg_types::ReferencePath::SiblingReference { sibling_key, .. } => Self::SiblingReference { + sibling_key: BytesView::new(sibling_key), + }, + } + } +} + +impl ReferencePath { + fn draw(&mut self, ui: &mut egui::Ui) { + match self { + ReferencePath::AbsolutePathReference { path, .. } => { + ui.label("Absolute path reference"); + for (i, segment) in path.iter_mut().enumerate() { + ui.horizontal(|line| { + line.label(i.to_string()); + segment.draw(line); + }); + } + } + ReferencePath::UpstreamRootHeightReference { + n_keep, path_append, .. + } => { + ui.label("Upstream root height reference"); + ui.label(format!("N keep: {n_keep}")); + for (i, segment) in path_append.iter_mut().enumerate() { + ui.horizontal(|line| { + line.label(i.to_string()); + segment.draw(line); + }); + } + } + ReferencePath::UpstreamRootHeightWithParentPathAdditionReference { + n_keep, path_append, .. + } => { + ui.label("Upstream root height with parent path addition reference"); + ui.label(format!("N keep: {n_keep}")); + for (i, segment) in path_append.iter_mut().enumerate() { + ui.horizontal(|line| { + line.label(i.to_string()); + segment.draw(line); + }); + } + } + ReferencePath::UpstreamFromElementHeightReference { + n_remove, + path_append, + .. + } => { + ui.label("Upstream from element height reference "); + ui.label(format!("N remove: {n_remove}")); + for (i, segment) in path_append.iter_mut().enumerate() { + ui.horizontal(|line| { + line.label(i.to_string()); + segment.draw(line); + }); + } + } + ReferencePath::CousinReference { swap_parent, .. } => { + ui.label("Cousin reference"); + swap_parent.draw(ui); + } + ReferencePath::RemovedCousinReference { swap_parent, .. } => { + ui.label("Removed cousin reference"); + for (i, segment) in swap_parent.iter_mut().enumerate() { + ui.horizontal(|line| { + line.label(i.to_string()); + segment.draw(line); + }); + } + } + ReferencePath::SiblingReference { sibling_key, .. } => { + ui.label("Sibling reference"); + sibling_key.draw(ui); + } + } + } +} + pub(crate) enum ElementViewer { Subtree { root_key: Option, @@ -326,44 +481,47 @@ pub(crate) enum ElementViewer { sum: i64, element_flags: Option, }, - Item { - value: BytesView, + BigSumtree { + root_key: Option, + sum: i128, element_flags: Option, }, - SumItem { - value: i64, + CountTree { + root_key: Option, + count: u64, element_flags: Option, }, - AbsolutePathReference { - path: Vec, + CountSumTree { + root_key: Option, + count: u64, + sum: i64, element_flags: Option, }, - UpstreamRootHeightReference { - n_keep: u32, - path_append: Vec, + Item { + value: BytesView, element_flags: Option, }, - UpstreamRootHeightWithParentPathAdditionReference { - n_keep: u32, - path_append: Vec, + ItemWithBackwardReferences { + value: BytesView, element_flags: Option, }, - UpstreamFromElementHeightReference { - n_remove: u32, - path_append: Vec, + SumItem { + value: i64, element_flags: Option, }, - CousinReference { - swap_parent: BytesView, + SumItemWithBackwardReferences { + value: i64, element_flags: Option, }, - RemovedCousinReference { - swap_parent: Vec, + Reference { + reference_path: ReferencePath, element_flags: Option, }, - SiblingReference { - sibling_key: BytesView, + BidirectionalReference { + reference_path: ReferencePath, element_flags: Option, + cascade_on_update: bool, + slot_idx: u8, }, } @@ -377,82 +535,83 @@ impl ElementViewer { root_key: root_key.map(|k| BytesView::new(k)), element_flags: element_flags.map(|f| BytesView::new(f)), }, - grovedbg_types::Element::Sumtree { + grovedbg_types::Element::CountTree { root_key, - sum, + count, element_flags, - } => ElementViewer::Sumtree { + .. + } => ElementViewer::CountTree { root_key: root_key.map(|k| BytesView::new(k)), - sum, - element_flags: element_flags.map(|f| BytesView::new(f)), - }, - grovedbg_types::Element::Item { value, element_flags } => ElementViewer::Item { - value: BytesView::new(value), + count, element_flags: element_flags.map(|f| BytesView::new(f)), }, - grovedbg_types::Element::SumItem { value, element_flags } => ElementViewer::SumItem { - value, - - element_flags: element_flags.map(|f| BytesView::new(f)), - }, - grovedbg_types::Element::Reference(grovedbg_types::Reference::AbsolutePathReference { - path, + grovedbg_types::Element::CountSumTree { + root_key, + count, + sum, element_flags, - }) => ElementViewer::AbsolutePathReference { - path: path.into_iter().map(|s| BytesView::new(s)).collect(), + .. + } => ElementViewer::CountSumTree { + root_key: root_key.map(|k| BytesView::new(k)), + count, + sum, element_flags: element_flags.map(|f| BytesView::new(f)), }, - grovedbg_types::Element::Reference(grovedbg_types::Reference::UpstreamRootHeightReference { - n_keep, - path_append, + grovedbg_types::Element::Sumtree { + root_key, + sum, element_flags, - }) => ElementViewer::UpstreamRootHeightReference { - n_keep, - path_append: path_append.into_iter().map(|s| BytesView::new(s)).collect(), + } => ElementViewer::Sumtree { + root_key: root_key.map(|k| BytesView::new(k)), + sum, element_flags: element_flags.map(|f| BytesView::new(f)), }, - grovedbg_types::Element::Reference( - grovedbg_types::Reference::UpstreamRootHeightWithParentPathAdditionReference { - n_keep, - path_append, - element_flags, - }, - ) => ElementViewer::UpstreamRootHeightWithParentPathAdditionReference { - n_keep, - path_append: path_append.into_iter().map(|s| BytesView::new(s)).collect(), + grovedbg_types::Element::BigSumTree { + root_key, + sum, + element_flags, + } => ElementViewer::BigSumtree { + root_key: root_key.map(|k| BytesView::new(k)), + sum, element_flags: element_flags.map(|f| BytesView::new(f)), }, - grovedbg_types::Element::Reference( - grovedbg_types::Reference::UpstreamFromElementHeightReference { - n_remove, - path_append, - element_flags, - }, - ) => ElementViewer::UpstreamFromElementHeightReference { - n_remove, - path_append: path_append.into_iter().map(|s| BytesView::new(s)).collect(), + grovedbg_types::Element::Item { value, element_flags } => ElementViewer::Item { + value: BytesView::new(value), element_flags: element_flags.map(|f| BytesView::new(f)), }, - grovedbg_types::Element::Reference(grovedbg_types::Reference::CousinReference { - swap_parent, - element_flags, - }) => ElementViewer::CousinReference { - swap_parent: BytesView::new(swap_parent), + grovedbg_types::Element::ItemWithBackwardReferences { value, element_flags } => { + ElementViewer::ItemWithBackwardReferences { + value: BytesView::new(value), + element_flags: element_flags.map(|f| BytesView::new(f)), + } + } + grovedbg_types::Element::SumItem { value, element_flags } => ElementViewer::SumItem { + value, element_flags: element_flags.map(|f| BytesView::new(f)), }, - grovedbg_types::Element::Reference(grovedbg_types::Reference::RemovedCousinReference { - swap_parent, + grovedbg_types::Element::SumItemWithBackwardReferences { value, element_flags } => { + ElementViewer::SumItemWithBackwardReferences { + value, + element_flags: element_flags.map(|f| BytesView::new(f)), + } + } + grovedbg_types::Element::Reference { + reference_path, element_flags, - }) => ElementViewer::RemovedCousinReference { - swap_parent: swap_parent.into_iter().map(|s| BytesView::new(s)).collect(), + } => ElementViewer::Reference { + reference_path: reference_path.into(), element_flags: element_flags.map(|f| BytesView::new(f)), }, - grovedbg_types::Element::Reference(grovedbg_types::Reference::SiblingReference { - sibling_key, + grovedbg_types::Element::BidirectionalReference { + reference_path, element_flags, - }) => ElementViewer::SiblingReference { - sibling_key: BytesView::new(sibling_key), + slot_idx, + cascade_on_update, + } => ElementViewer::BidirectionalReference { + reference_path: reference_path.into(), element_flags: element_flags.map(|f| BytesView::new(f)), + slot_idx, + cascade_on_update, }, } } @@ -488,28 +647,20 @@ impl ElementViewer { } } ElementViewer::Sumtree { - root_key: Some(key), + root_key, sum, element_flags, } => { - ui.label(format!("Sum tree: {sum}")); - ui.horizontal(|line| { - line.label("Root key:"); - key.draw(line); - }); - if let Some(flags) = element_flags { + if let Some(root_key) = root_key { + ui.label(format!("Sum tree: {sum}")); ui.horizontal(|line| { - line.label("Flags:"); - flags.draw(line); + line.label("Root key:"); + root_key.draw(line); }); + } else { + ui.label(format!("Empty sum tree: {sum}")); } - } - ElementViewer::Sumtree { - root_key: None, - sum, - element_flags, - } => { - ui.label(format!("Empty sum tree: {sum}")); + if let Some(flags) = element_flags { ui.horizontal(|line| { line.label("Flags:"); @@ -527,8 +678,9 @@ impl ElementViewer { }); } } - ElementViewer::SumItem { value, element_flags } => { - ui.label(format!("Sum item: {value}")); + ElementViewer::ItemWithBackwardReferences { value, element_flags } => { + ui.label("Item with backward references"); + value.draw(ui); if let Some(flags) = element_flags { ui.horizontal(|line| { line.label("Flags:"); @@ -536,14 +688,8 @@ impl ElementViewer { }); } } - ElementViewer::AbsolutePathReference { path, element_flags } => { - ui.label("Absolute path reference"); - for (i, segment) in path.iter_mut().enumerate() { - ui.horizontal(|line| { - line.label(i.to_string()); - segment.draw(line); - }); - } + ElementViewer::SumItem { value, element_flags } => { + ui.label(format!("Sum item: {value}")); if let Some(flags) = element_flags { ui.horizontal(|line| { line.label("Flags:"); @@ -551,19 +697,8 @@ impl ElementViewer { }); } } - ElementViewer::UpstreamRootHeightReference { - n_keep, - path_append, - element_flags, - } => { - ui.label("Upstream root height reference"); - ui.label(format!("N keep: {n_keep}")); - for (i, segment) in path_append.iter_mut().enumerate() { - ui.horizontal(|line| { - line.label(i.to_string()); - segment.draw(line); - }); - } + ElementViewer::SumItemWithBackwardReferences { value, element_flags } => { + ui.label(format!("Sum item with backward references: {value}")); if let Some(flags) = element_flags { ui.horizontal(|line| { line.label("Flags:"); @@ -571,19 +706,12 @@ impl ElementViewer { }); } } - ElementViewer::UpstreamRootHeightWithParentPathAdditionReference { - n_keep, - path_append, + ElementViewer::Reference { + reference_path, element_flags, } => { - ui.label("Upstream root height with parent path addition reference"); - ui.label(format!("N keep: {n_keep}")); - for (i, segment) in path_append.iter_mut().enumerate() { - ui.horizontal(|line| { - line.label(i.to_string()); - segment.draw(line); - }); - } + ui.label("Regular reference"); + reference_path.draw(ui); if let Some(flags) = element_flags { ui.horizontal(|line| { line.label("Flags:"); @@ -591,19 +719,16 @@ impl ElementViewer { }); } } - ElementViewer::UpstreamFromElementHeightReference { - n_remove, - path_append, + ElementViewer::BidirectionalReference { + reference_path, element_flags, + cascade_on_update, + slot_idx, } => { - ui.label("Upstream from element height reference "); - ui.label(format!("N remove: {n_remove}")); - for (i, segment) in path_append.iter_mut().enumerate() { - ui.horizontal(|line| { - line.label(i.to_string()); - segment.draw(line); - }); - } + ui.label("Bidirectional reference"); + reference_path.draw(ui); + ui.label(format!("Cascade on update: {cascade_on_update}")); + ui.label(format!("Backward ref slot: {slot_idx}")); if let Some(flags) = element_flags { ui.horizontal(|line| { line.label("Flags:"); @@ -611,12 +736,21 @@ impl ElementViewer { }); } } - ElementViewer::CousinReference { - swap_parent, + ElementViewer::BigSumtree { + root_key, + sum, element_flags, } => { - ui.label("Cousin reference"); - swap_parent.draw(ui); + if let Some(root_key) = root_key { + ui.label(format!("Big sum tree: {sum}")); + ui.horizontal(|line| { + line.label("Root key:"); + root_key.draw(line); + }); + } else { + ui.label(format!("Empty big sum tree: {sum}")); + } + if let Some(flags) = element_flags { ui.horizontal(|line| { line.label("Flags:"); @@ -624,17 +758,21 @@ impl ElementViewer { }); } } - ElementViewer::RemovedCousinReference { - swap_parent, + ElementViewer::CountTree { + root_key, + count, element_flags, } => { - ui.label("Removed cousin reference"); - for (i, segment) in swap_parent.iter_mut().enumerate() { + if let Some(root_key) = root_key { + ui.label(format!("Count tree: {count}")); ui.horizontal(|line| { - line.label(i.to_string()); - segment.draw(line); + line.label("Root key:"); + root_key.draw(line); }); + } else { + ui.label(format!("Empty count tree: {count}")); } + if let Some(flags) = element_flags { ui.horizontal(|line| { line.label("Flags:"); @@ -642,12 +780,22 @@ impl ElementViewer { }); } } - ElementViewer::SiblingReference { - sibling_key, + ElementViewer::CountSumTree { + root_key, + count, + sum, element_flags, } => { - ui.label("Sibling reference"); - sibling_key.draw(ui); + if let Some(root_key) = root_key { + ui.label(format!("Count sum tree: count {count}, sum {sum}")); + ui.horizontal(|line| { + line.label("Root key:"); + root_key.draw(line); + }); + } else { + ui.label(format!("Empty count sum tree: count {count}, sum {sum}")); + } + if let Some(flags) = element_flags { ui.horizontal(|line| { line.label("Flags:"); diff --git a/src/theme.rs b/src/theme.rs index a6b4a56..27b8016 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -12,6 +12,9 @@ const ERROR_COLOR_LIGHT: Color32 = Color32::DARK_RED; const REFERENCE_COLOR_LIGHT: Color32 = Color32::DARK_BLUE; const REFERENCE_COLOR_DARK: Color32 = Color32::LIGHT_BLUE; +const BIDI_REFERENCE_COLOR_LIGHT: Color32 = Color32::from_rgb(0, 0x9E, 0x9E); +const BIDI_REFERENCE_COLOR_DARK: Color32 = Color32::from_rgb(0, 0x9E, 0x9E); + const PROOF_NODE_COLOR_LIGHT: Color32 = Color32::from_rgb(143, 0, 179); const PROOF_NODE_COLOR_DARK: Color32 = Color32::from_rgb(215, 119, 240); @@ -20,21 +23,45 @@ pub(crate) fn element_to_color(ctx: &Context, element: &ElementOrPlaceholder) -> // Dark theme match element { ElementOrPlaceholder::Placeholder => Color32::RED, - ElementOrPlaceholder::Element(Element::Item { .. }) => Color32::GRAY, - ElementOrPlaceholder::Element(Element::SumItem { .. }) => Color32::DARK_GREEN, + ElementOrPlaceholder::Element( + Element::Item { .. } | Element::ItemWithBackwardReferences { .. }, + ) => Color32::GRAY, + ElementOrPlaceholder::Element( + Element::SumItem { .. } | Element::SumItemWithBackwardReferences { .. }, + ) => Color32::DARK_GREEN, ElementOrPlaceholder::Element(Element::Subtree { .. }) => SUBTREE_COLOR_DARK, - ElementOrPlaceholder::Element(Element::Sumtree { .. }) => Color32::GREEN, - ElementOrPlaceholder::Element(Element::Reference(..)) => REFERENCE_COLOR_DARK, + ElementOrPlaceholder::Element( + Element::Sumtree { .. } + | Element::BigSumTree { .. } + | Element::CountTree { .. } + | Element::CountSumTree { .. }, + ) => Color32::GREEN, + ElementOrPlaceholder::Element(Element::Reference { .. }) => REFERENCE_COLOR_DARK, + ElementOrPlaceholder::Element(Element::BidirectionalReference { .. }) => { + BIDI_REFERENCE_COLOR_DARK + } } } else { // Light theme match element { ElementOrPlaceholder::Placeholder => Color32::DARK_RED, - ElementOrPlaceholder::Element(Element::Item { .. }) => Color32::GRAY, - ElementOrPlaceholder::Element(Element::SumItem { .. }) => Color32::DARK_GREEN, + ElementOrPlaceholder::Element( + Element::Item { .. } | Element::ItemWithBackwardReferences { .. }, + ) => Color32::GRAY, + ElementOrPlaceholder::Element( + Element::SumItem { .. } | Element::SumItemWithBackwardReferences { .. }, + ) => Color32::DARK_GREEN, ElementOrPlaceholder::Element(Element::Subtree { .. }) => SUBTREE_COLOR_LIGHT, - ElementOrPlaceholder::Element(Element::Sumtree { .. }) => Color32::from_rgb(0, 150, 0), - ElementOrPlaceholder::Element(Element::Reference(..)) => REFERENCE_COLOR_LIGHT, + ElementOrPlaceholder::Element( + Element::Sumtree { .. } + | Element::BigSumTree { .. } + | Element::CountTree { .. } + | Element::CountSumTree { .. }, + ) => Color32::from_rgb(0, 150, 0), + ElementOrPlaceholder::Element(Element::Reference { .. }) => REFERENCE_COLOR_LIGHT, + ElementOrPlaceholder::Element(Element::BidirectionalReference { .. }) => { + BIDI_REFERENCE_COLOR_LIGHT + } } } } @@ -55,6 +82,14 @@ pub(crate) fn reference_line_color(ctx: &Context) -> Color32 { } } +pub(crate) fn bidi_reference_line_color(ctx: &Context) -> Color32 { + if ctx.style().visuals.dark_mode { + BIDI_REFERENCE_COLOR_DARK + } else { + BIDI_REFERENCE_COLOR_LIGHT + } +} + pub(crate) fn input_error_color(ctx: &Context) -> Color32 { if ctx.style().visuals.dark_mode { ERROR_COLOR_DARK diff --git a/src/tree_view/element_view.rs b/src/tree_view/element_view.rs index a2e7b2a..f2f7295 100644 --- a/src/tree_view/element_view.rs +++ b/src/tree_view/element_view.rs @@ -5,7 +5,7 @@ use std::collections::BTreeSet; use eframe::egui::{self, Context, Label, Layout, RichText, Vec2}; use grovedb_epoch_based_storage_flags::StorageFlags; use grovedbg_types::{CryptoHash, Element, Key}; -use reference_view::draw_reference; +use reference_view::{draw_bidi_reference, draw_reference}; use super::{ElementViewContext, NODE_WIDTH}; use crate::{ @@ -160,7 +160,11 @@ impl ElementView { layout, |value_ui: &mut egui::Ui| { match &self.value { - ElementOrPlaceholder::Element(Element::Item { value, element_flags }) => { + // TODO items with backward references shall have some hints + ElementOrPlaceholder::Element( + Element::Item { value, element_flags } + | Element::ItemWithBackwardReferences { value, element_flags }, + ) => { let mut profile_display = element_view_context.profile_ctx().value_display(&self.key); let display = profile_display.as_mut().unwrap_or(&mut self.value_display); @@ -186,7 +190,10 @@ impl ElementView { }); } } - ElementOrPlaceholder::Element(Element::SumItem { value, element_flags }) => { + ElementOrPlaceholder::Element( + Element::SumItem { value, element_flags } + | Element::SumItemWithBackwardReferences { value, element_flags }, + ) => { value_ui.label(format!("Value: {value}")); if let Some(flags) = element_flags { @@ -201,12 +208,16 @@ impl ElementView { }); } } - ElementOrPlaceholder::Element(Element::Reference(reference)) => { + ElementOrPlaceholder::Element(Element::Reference { + reference_path, + element_flags, + }) => { draw_reference( value_ui, element_view_context, &self.key, - reference, + reference_path, + element_flags.as_deref(), &mut self.show_reference_details, &mut self.flags_display, subtrees_map, @@ -235,6 +246,48 @@ impl ElementView { value_ui.label("Bad reference"); }); } + ElementOrPlaceholder::Element(Element::BidirectionalReference { + reference_path, + element_flags, + slot_idx, + cascade_on_update, + }) => { + draw_bidi_reference( + value_ui, + element_view_context, + &self.key, + reference_path, + *slot_idx, + *cascade_on_update, + element_flags.as_deref(), + &mut self.show_reference_details, + &mut self.flags_display, + subtrees_map, + ) + .inspect_err(|e| { + let path_display = element_view_context.path().for_segments(|segments_iter| { + full_path_display(full_path_display_iter( + segments_iter, + element_view_context.profile_ctx(), + )) + }); + + log::warn!( + "Bad bidirectional reference at {} under the key {}, {}", + path_display, + bytes_by_display_variant( + &self.key, + &path_with_key + .get_display_variant() + .unwrap_or_else(|| BytesDisplayVariant::guess(&self.key)), + ), + e.0, + ); + }) + .unwrap_or_else(|_| { + value_ui.label("Bad bidirectional reference"); + }); + } ElementOrPlaceholder::Element(Element::Sumtree { sum, element_flags, .. }) => { @@ -269,6 +322,111 @@ impl ElementView { }); } } + ElementOrPlaceholder::Element(Element::BigSumTree { + sum, element_flags, .. + }) => { + value_ui.horizontal(|line| { + let mut checkbox = visibility.contains(&self.key); + let checkbox_before = checkbox; + + line.checkbox(&mut checkbox, ""); + + if checkbox_before != checkbox { + if checkbox { + visibility.insert(self.key.clone()); + } else { + visibility.remove(&self.key); + } + } + + if line.button(egui_phosphor::regular::MAGNIFYING_GLASS).clicked() { + element_view_context.focus_child_subtree(self.key.clone()); + } + line.label(format!("Big sum: {sum}")); + }); + if let Some(flags) = element_flags { + value_ui.horizontal(|line| { + line.label("Flags:"); + if let Some(storage_flags) = StorageFlags::deserialize(&flags).ok().flatten() + { + line.label(format!("{storage_flags}")); + } else { + binary_label(line, flags, &mut self.flags_display); + } + }); + } + } + ElementOrPlaceholder::Element(Element::CountTree { + count, element_flags, .. + }) => { + value_ui.horizontal(|line| { + let mut checkbox = visibility.contains(&self.key); + let checkbox_before = checkbox; + + line.checkbox(&mut checkbox, ""); + + if checkbox_before != checkbox { + if checkbox { + visibility.insert(self.key.clone()); + } else { + visibility.remove(&self.key); + } + } + + if line.button(egui_phosphor::regular::MAGNIFYING_GLASS).clicked() { + element_view_context.focus_child_subtree(self.key.clone()); + } + line.label(format!("Count: {count}")); + }); + if let Some(flags) = element_flags { + value_ui.horizontal(|line| { + line.label("Flags:"); + if let Some(storage_flags) = StorageFlags::deserialize(&flags).ok().flatten() + { + line.label(format!("{storage_flags}")); + } else { + binary_label(line, flags, &mut self.flags_display); + } + }); + } + } + ElementOrPlaceholder::Element(Element::CountSumTree { + count, + sum, + element_flags, + .. + }) => { + value_ui.horizontal(|line| { + let mut checkbox = visibility.contains(&self.key); + let checkbox_before = checkbox; + + line.checkbox(&mut checkbox, ""); + + if checkbox_before != checkbox { + if checkbox { + visibility.insert(self.key.clone()); + } else { + visibility.remove(&self.key); + } + } + + if line.button(egui_phosphor::regular::MAGNIFYING_GLASS).clicked() { + element_view_context.focus_child_subtree(self.key.clone()); + } + line.label(format!("Count: {count}, Sum: {sum}")); + }); + if let Some(flags) = element_flags { + value_ui.horizontal(|line| { + line.label("Flags:"); + if let Some(storage_flags) = StorageFlags::deserialize(&flags).ok().flatten() + { + line.label(format!("{storage_flags}")); + } else { + binary_label(line, flags, &mut self.flags_display); + } + }); + } + } ElementOrPlaceholder::Element(Element::Subtree { element_flags, .. }) => { value_ui.horizontal(|line| { let mut checkbox = visibility.contains(&self.key); diff --git a/src/tree_view/element_view/reference_view.rs b/src/tree_view/element_view/reference_view.rs index ba43570..3c813bf 100644 --- a/src/tree_view/element_view/reference_view.rs +++ b/src/tree_view/element_view/reference_view.rs @@ -1,13 +1,13 @@ use std::{borrow::Cow, cmp, fmt::Write}; -use eframe::egui::{self, Painter, Pos2, Stroke, Vec2}; +use eframe::egui::{self, Color32, Painter, Pos2, Stroke, Vec2}; use grovedb_epoch_based_storage_flags::StorageFlags; -use grovedbg_types::Reference; +use grovedbg_types::ReferencePath; use crate::{ bytes_utils::{binary_label, bytes_by_display_variant, BytesDisplayVariant}, path_ctx::{path_label, Path}, - theme::reference_line_color, + theme::{bidi_reference_line_color, reference_line_color}, tree_data::SubtreeDataMap, tree_view::ElementViewContext, }; @@ -18,10 +18,69 @@ pub(super) fn draw_reference( ui: &mut egui::Ui, element_view_context: &mut ElementViewContext, key: &[u8], - reference: &Reference, + reference: &ReferencePath, + flags: Option<&[u8]>, show_details: &mut bool, flags_display: &mut BytesDisplayVariant, subtrees_map: &SubtreeDataMap, +) -> Result<(), ReferenceError> { + let color = reference_line_color(ui.ctx()); + draw_reference_internal( + ui, + element_view_context, + key, + reference, + flags, + show_details, + flags_display, + subtrees_map, + None, + color, + ) +} + +pub(super) fn draw_bidi_reference( + ui: &mut egui::Ui, + element_view_context: &mut ElementViewContext, + key: &[u8], + reference: &ReferencePath, + slot_idx: u8, + cascade_on_update: bool, + flags: Option<&[u8]>, + show_details: &mut bool, + flags_display: &mut BytesDisplayVariant, + subtrees_map: &SubtreeDataMap, +) -> Result<(), ReferenceError> { + let color = bidi_reference_line_color(ui.ctx()); + let bidi_details = BidiDetails { + cascade_on_update, + slot_idx, + }; + draw_reference_internal( + ui, + element_view_context, + key, + reference, + flags, + show_details, + flags_display, + subtrees_map, + Some(bidi_details), + color, + ) +} + +fn draw_reference_internal( + ui: &mut egui::Ui, + element_view_context: &mut ElementViewContext, + key: &[u8], + reference: &ReferencePath, + flags: Option<&[u8]>, + show_details: &mut bool, + flags_display: &mut BytesDisplayVariant, + subtrees_map: &SubtreeDataMap, + bidi_details: Option, // todo: refactor + color: Color32, ) -> Result<(), ReferenceError> { let (referenced_path, referenced_key) = get_absolute_path_key(element_view_context.path(), key, reference)?; @@ -72,16 +131,6 @@ pub(super) fn draw_reference( )); }); - let flags = match reference { - Reference::AbsolutePathReference { element_flags, .. } => element_flags, - Reference::UpstreamRootHeightReference { element_flags, .. } => element_flags, - Reference::UpstreamRootHeightWithParentPathAdditionReference { element_flags, .. } => element_flags, - Reference::UpstreamFromElementHeightReference { element_flags, .. } => element_flags, - Reference::CousinReference { element_flags, .. } => element_flags, - Reference::RemovedCousinReference { element_flags, .. } => element_flags, - Reference::SiblingReference { element_flags, .. } => element_flags, - }; - if let Some(flags) = flags { ui.horizontal(|line| { line.label("Flags:"); @@ -94,7 +143,7 @@ pub(super) fn draw_reference( } if *show_details { - draw_reference_details(ui, reference); + draw_reference_details(ui, reference, bidi_details); } // Draw reference arrow @@ -142,15 +191,7 @@ pub(super) fn draw_reference( ) } }; - arrow( - painter, - from, - to - from, - Stroke { - width: 1.0, - color: reference_line_color(ui.ctx()), - }, - ); + arrow(painter, from, to - from, Stroke { width: 1.0, color }); } Ok(()) @@ -168,27 +209,35 @@ fn arrow(painter: &Painter, origin: Pos2, vec: Vec2, stroke: impl Into) painter.line_segment([tip, tip - tip_length * (rot.inverse() * dir)], stroke); } -fn draw_reference_details(ui: &mut egui::Ui, reference: &Reference) { +struct BidiDetails { + cascade_on_update: bool, + slot_idx: u8, +} + +fn draw_reference_details(ui: &mut egui::Ui, reference: &ReferencePath, bidi_details: Option) { + if bidi_details.is_some() { + ui.label("Bidirectional reference"); + } match reference { - Reference::AbsolutePathReference { path, .. } => { + ReferencePath::AbsolutePathReference { path, .. } => { ui.label("Absolute path"); ui.label(format!("Path: {}", hex_array(path))); } - Reference::UpstreamRootHeightReference { + ReferencePath::UpstreamRootHeightReference { n_keep, path_append, .. } => { ui.label("Upstream root height"); ui.label(format!("N keep: {n_keep}")); ui.label(format!("Path append: {}", hex_array(path_append))); } - Reference::UpstreamRootHeightWithParentPathAdditionReference { + ReferencePath::UpstreamRootHeightWithParentPathAdditionReference { n_keep, path_append, .. } => { ui.label("Upstream root height with parent path addition"); ui.label(format!("N keep: {n_keep}")); ui.label(format!("Path append: {}", hex_array(path_append))); } - Reference::UpstreamFromElementHeightReference { + ReferencePath::UpstreamFromElementHeightReference { n_remove, path_append, .. @@ -197,19 +246,24 @@ fn draw_reference_details(ui: &mut egui::Ui, reference: &Reference) { ui.label(format!("N remove: {n_remove}")); ui.label(format!("Path append: {}", hex_array(path_append))); } - Reference::CousinReference { swap_parent, .. } => { + ReferencePath::CousinReference { swap_parent, .. } => { ui.label("Cousin"); ui.label(format!("Swap parent: {}", hex::encode(swap_parent))); } - Reference::RemovedCousinReference { swap_parent, .. } => { + ReferencePath::RemovedCousinReference { swap_parent, .. } => { ui.label("Removed cousin"); ui.label(format!("Swap parent: {}", hex_array(swap_parent))); } - Reference::SiblingReference { sibling_key, .. } => { + ReferencePath::SiblingReference { sibling_key, .. } => { ui.label("Sibling"); ui.label(format!("Sibling key: {}", hex::encode(sibling_key))); } } + + if let Some(bidi) = bidi_details { + ui.label(format!("Cascade on update: {}", bidi.cascade_on_update)); + ui.label(format!("Backward reference slot: {}", bidi.slot_idx)); + } } fn hex_array(byte_slices: &[impl AsRef<[u8]>]) -> String { @@ -234,17 +288,17 @@ pub(super) struct ReferenceError(pub(super) &'static str); fn get_absolute_path_key<'a, 'b>( current_path: Path<'a>, current_key: &'b [u8], - reference: &'b Reference, + reference: &'b ReferencePath, ) -> Result<(Path<'a>, Cow<'b, [u8]>), ReferenceError> { match reference { - Reference::AbsolutePathReference { path, .. } => { + ReferencePath::AbsolutePathReference { path, .. } => { let mut path = path.iter(); let key = path .next_back() .ok_or_else(|| ReferenceError("empty absolute reference"))?; Ok((current_path.get_ctx().add_iter(path), key.into())) } - Reference::UpstreamRootHeightReference { + ReferencePath::UpstreamRootHeightReference { n_keep, path_append, .. } => { if (*n_keep as usize) > current_path.level() { @@ -265,7 +319,7 @@ fn get_absolute_path_key<'a, 'b>( .map(|(path, key)| (path, key.into())) .ok_or_else(|| ReferenceError("the computed absolute path is empty")) } - Reference::UpstreamRootHeightWithParentPathAdditionReference { + ReferencePath::UpstreamRootHeightWithParentPathAdditionReference { n_keep, path_append, .. } => { if (*n_keep as usize) > current_path.level() { @@ -288,7 +342,7 @@ fn get_absolute_path_key<'a, 'b>( .map(|(path, key)| (path, key.into())) .ok_or_else(|| ReferenceError("the computed absolute path is empty")) } - Reference::UpstreamFromElementHeightReference { + ReferencePath::UpstreamFromElementHeightReference { n_remove, path_append, .. @@ -314,14 +368,14 @@ fn get_absolute_path_key<'a, 'b>( .map(|(path, key)| (path, key.into())) .ok_or_else(|| ReferenceError("the computed absolute path is empty")) } - Reference::CousinReference { swap_parent, .. } => Ok(( + ReferencePath::CousinReference { swap_parent, .. } => Ok(( current_path .parent() .ok_or_else(|| ReferenceError("no parent to swap"))? .child(swap_parent.to_vec()), current_key.into(), )), - Reference::RemovedCousinReference { swap_parent, .. } => { + ReferencePath::RemovedCousinReference { swap_parent, .. } => { let mut new_path = current_path .parent() .ok_or_else(|| ReferenceError("can't swap parent of an empty path"))?; @@ -330,6 +384,6 @@ fn get_absolute_path_key<'a, 'b>( } Ok((new_path, current_key.into())) } - Reference::SiblingReference { sibling_key, .. } => Ok((current_path, sibling_key.into())), + ReferencePath::SiblingReference { sibling_key, .. } => Ok((current_path, sibling_key.into())), } }