WIP commit, migrating workspace serialization code into the workspace

Mikayla Maki created

Change summary

crates/db/src/db.rs                  |   3 
crates/db/src/workspace/model.rs     | 257 -----------------------------
crates/workspace/src/workspace.rs    |   9 
crates/workspace/src/workspace_db.rs | 262 +++++++++++++++++++++++++++++
4 files changed, 266 insertions(+), 265 deletions(-)

Detailed changes

crates/db/src/db.rs 🔗

@@ -1,5 +1,4 @@
 pub mod kvp;
-pub mod workspace;
 
 use std::fs;
 use std::ops::Deref;
@@ -11,8 +10,6 @@ use sqlez::connection::Connection;
 use sqlez::domain::Domain;
 use sqlez::thread_safe_connection::ThreadSafeConnection;
 
-pub use workspace::*;
-
 const INITIALIZE_QUERY: &'static str = indoc! {"
     PRAGMA journal_mode=WAL;
     PRAGMA synchronous=NORMAL;

crates/db/src/workspace/model.rs 🔗

@@ -1,257 +0,0 @@
-use std::{
-    path::{Path, PathBuf},
-    sync::Arc,
-};
-
-use anyhow::{bail, Result};
-
-use sqlez::{
-    bindable::{Bind, Column},
-    statement::Statement,
-};
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub(crate) struct WorkspaceId(Vec<PathBuf>);
-
-impl WorkspaceId {
-    pub fn paths(self) -> Vec<PathBuf> {
-        self.0
-    }
-}
-
-impl<P: AsRef<Path>, T: IntoIterator<Item = P>> From<T> for WorkspaceId {
-    fn from(iterator: T) -> Self {
-        let mut roots = iterator
-            .into_iter()
-            .map(|p| p.as_ref().to_path_buf())
-            .collect::<Vec<_>>();
-        roots.sort();
-        Self(roots)
-    }
-}
-
-impl Bind for &WorkspaceId {
-    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
-        bincode::serialize(&self.0)
-            .expect("Bincode serialization of paths should not fail")
-            .bind(statement, start_index)
-    }
-}
-
-impl Column for WorkspaceId {
-    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
-        let blob = statement.column_blob(start_index)?;
-        Ok((WorkspaceId(bincode::deserialize(blob)?), start_index + 1))
-    }
-}
-
-#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
-pub enum DockAnchor {
-    #[default]
-    Bottom,
-    Right,
-    Expanded,
-}
-
-impl Bind for DockAnchor {
-    fn bind(&self, statement: &Statement, start_index: i32) -> anyhow::Result<i32> {
-        match self {
-            DockAnchor::Bottom => "Bottom",
-            DockAnchor::Right => "Right",
-            DockAnchor::Expanded => "Expanded",
-        }
-        .bind(statement, start_index)
-    }
-}
-
-impl Column for DockAnchor {
-    fn column(statement: &mut Statement, start_index: i32) -> anyhow::Result<(Self, i32)> {
-        String::column(statement, start_index).and_then(|(anchor_text, next_index)| {
-            Ok((
-                match anchor_text.as_ref() {
-                    "Bottom" => DockAnchor::Bottom,
-                    "Right" => DockAnchor::Right,
-                    "Expanded" => DockAnchor::Expanded,
-                    _ => bail!("Stored dock anchor is incorrect"),
-                },
-                next_index,
-            ))
-        })
-    }
-}
-
-#[derive(Debug, PartialEq, Eq)]
-pub struct SerializedWorkspace {
-    pub dock_anchor: DockAnchor,
-    pub dock_visible: bool,
-    pub center_group: SerializedPaneGroup,
-    pub dock_pane: SerializedPane,
-}
-
-#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
-pub enum Axis {
-    #[default]
-    Horizontal,
-    Vertical,
-}
-
-impl Bind for Axis {
-    fn bind(&self, statement: &Statement, start_index: i32) -> anyhow::Result<i32> {
-        match self {
-            Axis::Horizontal => "Horizontal",
-            Axis::Vertical => "Vertical",
-        }
-        .bind(statement, start_index)
-    }
-}
-
-impl Column for Axis {
-    fn column(statement: &mut Statement, start_index: i32) -> anyhow::Result<(Self, i32)> {
-        String::column(statement, start_index).and_then(|(axis_text, next_index)| {
-            Ok((
-                match axis_text.as_str() {
-                    "Horizontal" => Axis::Horizontal,
-                    "Vertical" => Axis::Vertical,
-                    _ => bail!("Stored serialized item kind is incorrect"),
-                },
-                next_index,
-            ))
-        })
-    }
-}
-
-#[derive(Debug, PartialEq, Eq, Clone)]
-pub enum SerializedPaneGroup {
-    Group {
-        axis: Axis,
-        children: Vec<SerializedPaneGroup>,
-    },
-    Pane(SerializedPane),
-}
-
-// Dock panes, and grouped panes combined?
-// AND we're collapsing PaneGroup::Pane
-// In the case where
-
-impl Default for SerializedPaneGroup {
-    fn default() -> Self {
-        Self::Group {
-            axis: Axis::Horizontal,
-            children: vec![Self::Pane(Default::default())],
-        }
-    }
-}
-
-#[derive(Debug, PartialEq, Eq, Default, Clone)]
-pub struct SerializedPane {
-    pub(crate) children: Vec<SerializedItem>,
-}
-
-impl SerializedPane {
-    pub fn new(children: Vec<SerializedItem>) -> Self {
-        SerializedPane { children }
-    }
-}
-
-pub type GroupId = i64;
-pub type PaneId = i64;
-pub type ItemId = usize;
-
-pub(crate) enum SerializedItemKind {
-    Editor,
-    Diagnostics,
-    ProjectSearch,
-    Terminal,
-}
-
-impl Bind for SerializedItemKind {
-    fn bind(&self, statement: &Statement, start_index: i32) -> anyhow::Result<i32> {
-        match self {
-            SerializedItemKind::Editor => "Editor",
-            SerializedItemKind::Diagnostics => "Diagnostics",
-            SerializedItemKind::ProjectSearch => "ProjectSearch",
-            SerializedItemKind::Terminal => "Terminal",
-        }
-        .bind(statement, start_index)
-    }
-}
-
-impl Column for SerializedItemKind {
-    fn column(statement: &mut Statement, start_index: i32) -> anyhow::Result<(Self, i32)> {
-        String::column(statement, start_index).and_then(|(kind_text, next_index)| {
-            Ok((
-                match kind_text.as_ref() {
-                    "Editor" => SerializedItemKind::Editor,
-                    "Diagnostics" => SerializedItemKind::Diagnostics,
-                    "ProjectSearch" => SerializedItemKind::ProjectSearch,
-                    "Terminal" => SerializedItemKind::Terminal,
-                    _ => bail!("Stored serialized item kind is incorrect"),
-                },
-                next_index,
-            ))
-        })
-    }
-}
-
-#[derive(Debug, PartialEq, Eq, Clone)]
-pub enum SerializedItem {
-    Editor { item_id: usize, path: Arc<Path> },
-    Diagnostics { item_id: usize },
-    ProjectSearch { item_id: usize, query: String },
-    Terminal { item_id: usize },
-}
-
-impl SerializedItem {
-    pub fn item_id(&self) -> usize {
-        match self {
-            SerializedItem::Editor { item_id, .. } => *item_id,
-            SerializedItem::Diagnostics { item_id } => *item_id,
-            SerializedItem::ProjectSearch { item_id, .. } => *item_id,
-            SerializedItem::Terminal { item_id } => *item_id,
-        }
-    }
-
-    pub(crate) fn kind(&self) -> SerializedItemKind {
-        match self {
-            SerializedItem::Editor { .. } => SerializedItemKind::Editor,
-            SerializedItem::Diagnostics { .. } => SerializedItemKind::Diagnostics,
-            SerializedItem::ProjectSearch { .. } => SerializedItemKind::ProjectSearch,
-            SerializedItem::Terminal { .. } => SerializedItemKind::Terminal,
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use sqlez::connection::Connection;
-
-    use crate::model::DockAnchor;
-
-    use super::WorkspaceId;
-
-    #[test]
-    fn test_workspace_round_trips() {
-        let db = Connection::open_memory("workspace_id_round_trips");
-
-        db.exec(indoc::indoc! {"
-            CREATE TABLE workspace_id_test(
-                workspace_id BLOB,
-                dock_anchor TEXT
-            );"})
-            .unwrap()()
-        .unwrap();
-
-        let workspace_id: WorkspaceId = WorkspaceId::from(&["\test2", "\test1"]);
-
-        db.exec_bound("INSERT INTO workspace_id_test(workspace_id, dock_anchor) VALUES (?,?)")
-            .unwrap()((&workspace_id, DockAnchor::Bottom))
-        .unwrap();
-
-        assert_eq!(
-            db.select_row("SELECT workspace_id, dock_anchor FROM workspace_id_test LIMIT 1")
-                .unwrap()()
-            .unwrap(),
-            Some((WorkspaceId::from(&["\test1", "\test2"]), DockAnchor::Bottom))
-        );
-    }
-}

crates/workspace/src/workspace.rs 🔗

@@ -10,12 +10,13 @@ pub mod shared_screen;
 pub mod sidebar;
 mod status_bar;
 mod toolbar;
+mod workspace_db;
 
 use anyhow::{anyhow, Context, Result};
 use call::ActiveCall;
 use client::{proto, Client, PeerId, TypedEnvelope, UserStore};
 use collections::{hash_map, HashMap, HashSet};
-use db::{kvp::KeyValue, model::SerializedWorkspace, Db};
+use db::{kvp::KeyValue, Db};
 use dock::{DefaultItemFactory, Dock, ToggleDockButton};
 use drag_and_drop::DragAndDrop;
 use fs::{self, Fs};
@@ -61,6 +62,8 @@ use theme::{Theme, ThemeRegistry};
 pub use toolbar::{ToolbarItemLocation, ToolbarItemView};
 use util::ResultExt;
 
+use crate::workspace_db::model;
+
 type ProjectItemBuilders = HashMap<
     TypeId,
     fn(ModelHandle<Project>, AnyModelHandle, &mut ViewContext<Pane>) -> Box<dyn ItemHandle>,
@@ -1120,7 +1123,7 @@ enum FollowerItem {
 
 impl Workspace {
     pub fn new(
-        _serialized_workspace: Option<SerializedWorkspace>,
+        _serialized_workspace: Option<isize>,
         project: ModelHandle<Project>,
         dock_default_factory: DefaultItemFactory,
         cx: &mut ViewContext<Self>,
@@ -1289,7 +1292,7 @@ impl Workspace {
             // Use the resolved worktree roots to get the serialized_db from the database
             let serialized_workspace = cx.read(|cx| {
                 cx.global::<Db<KeyValue>>()
-                    .open_as::<db::Workspace>()
+                    .open_as::<model::Workspace>()
                     .workspace_for_roots(&Vec::from_iter(worktree_roots.into_iter())[..])
             });
 

crates/db/src/workspace.rs → crates/workspace/src/workspace_db.rs 🔗

@@ -1,5 +1,3 @@
-pub mod model;
-
 use anyhow::{bail, Context, Result};
 use util::{iife, unzip_option, ResultExt};
 
@@ -493,3 +491,263 @@ mod tests {
         assert_eq!(workspace.center_group, center_pane);
     }
 }
+
+pub mod model {
+    use std::{
+        path::{Path, PathBuf},
+        sync::Arc,
+    };
+
+    use anyhow::{bail, Result};
+
+    use sqlez::{
+        bindable::{Bind, Column},
+        statement::Statement,
+    };
+
+    #[derive(Debug, Clone, PartialEq, Eq)]
+    pub(crate) struct WorkspaceId(Vec<PathBuf>);
+
+    impl WorkspaceId {
+        pub fn paths(self) -> Vec<PathBuf> {
+            self.0
+        }
+    }
+
+    impl<P: AsRef<Path>, T: IntoIterator<Item = P>> From<T> for WorkspaceId {
+        fn from(iterator: T) -> Self {
+            let mut roots = iterator
+                .into_iter()
+                .map(|p| p.as_ref().to_path_buf())
+                .collect::<Vec<_>>();
+            roots.sort();
+            Self(roots)
+        }
+    }
+
+    impl Bind for &WorkspaceId {
+        fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
+            bincode::serialize(&self.0)
+                .expect("Bincode serialization of paths should not fail")
+                .bind(statement, start_index)
+        }
+    }
+
+    impl Column for WorkspaceId {
+        fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
+            let blob = statement.column_blob(start_index)?;
+            Ok((WorkspaceId(bincode::deserialize(blob)?), start_index + 1))
+        }
+    }
+
+    #[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
+    pub enum DockAnchor {
+        #[default]
+        Bottom,
+        Right,
+        Expanded,
+    }
+
+    impl Bind for DockAnchor {
+        fn bind(&self, statement: &Statement, start_index: i32) -> anyhow::Result<i32> {
+            match self {
+                DockAnchor::Bottom => "Bottom",
+                DockAnchor::Right => "Right",
+                DockAnchor::Expanded => "Expanded",
+            }
+            .bind(statement, start_index)
+        }
+    }
+
+    impl Column for DockAnchor {
+        fn column(statement: &mut Statement, start_index: i32) -> anyhow::Result<(Self, i32)> {
+            String::column(statement, start_index).and_then(|(anchor_text, next_index)| {
+                Ok((
+                    match anchor_text.as_ref() {
+                        "Bottom" => DockAnchor::Bottom,
+                        "Right" => DockAnchor::Right,
+                        "Expanded" => DockAnchor::Expanded,
+                        _ => bail!("Stored dock anchor is incorrect"),
+                    },
+                    next_index,
+                ))
+            })
+        }
+    }
+
+    #[derive(Debug, PartialEq, Eq)]
+    pub struct SerializedWorkspace {
+        pub dock_anchor: DockAnchor,
+        pub dock_visible: bool,
+        pub center_group: SerializedPaneGroup,
+        pub dock_pane: SerializedPane,
+    }
+
+    #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
+    pub enum Axis {
+        #[default]
+        Horizontal,
+        Vertical,
+    }
+
+    impl Bind for Axis {
+        fn bind(&self, statement: &Statement, start_index: i32) -> anyhow::Result<i32> {
+            match self {
+                Axis::Horizontal => "Horizontal",
+                Axis::Vertical => "Vertical",
+            }
+            .bind(statement, start_index)
+        }
+    }
+
+    impl Column for Axis {
+        fn column(statement: &mut Statement, start_index: i32) -> anyhow::Result<(Self, i32)> {
+            String::column(statement, start_index).and_then(|(axis_text, next_index)| {
+                Ok((
+                    match axis_text.as_str() {
+                        "Horizontal" => Axis::Horizontal,
+                        "Vertical" => Axis::Vertical,
+                        _ => bail!("Stored serialized item kind is incorrect"),
+                    },
+                    next_index,
+                ))
+            })
+        }
+    }
+
+    #[derive(Debug, PartialEq, Eq, Clone)]
+    pub enum SerializedPaneGroup {
+        Group {
+            axis: Axis,
+            children: Vec<SerializedPaneGroup>,
+        },
+        Pane(SerializedPane),
+    }
+
+    // Dock panes, and grouped panes combined?
+    // AND we're collapsing PaneGroup::Pane
+    // In the case where
+
+    impl Default for SerializedPaneGroup {
+        fn default() -> Self {
+            Self::Group {
+                axis: Axis::Horizontal,
+                children: vec![Self::Pane(Default::default())],
+            }
+        }
+    }
+
+    #[derive(Debug, PartialEq, Eq, Default, Clone)]
+    pub struct SerializedPane {
+        pub(crate) children: Vec<SerializedItem>,
+    }
+
+    impl SerializedPane {
+        pub fn new(children: Vec<SerializedItem>) -> Self {
+            SerializedPane { children }
+        }
+    }
+
+    pub type GroupId = i64;
+    pub type PaneId = i64;
+    pub type ItemId = usize;
+
+    pub(crate) enum SerializedItemKind {
+        Editor,
+        Diagnostics,
+        ProjectSearch,
+        Terminal,
+    }
+
+    impl Bind for SerializedItemKind {
+        fn bind(&self, statement: &Statement, start_index: i32) -> anyhow::Result<i32> {
+            match self {
+                SerializedItemKind::Editor => "Editor",
+                SerializedItemKind::Diagnostics => "Diagnostics",
+                SerializedItemKind::ProjectSearch => "ProjectSearch",
+                SerializedItemKind::Terminal => "Terminal",
+            }
+            .bind(statement, start_index)
+        }
+    }
+
+    impl Column for SerializedItemKind {
+        fn column(statement: &mut Statement, start_index: i32) -> anyhow::Result<(Self, i32)> {
+            String::column(statement, start_index).and_then(|(kind_text, next_index)| {
+                Ok((
+                    match kind_text.as_ref() {
+                        "Editor" => SerializedItemKind::Editor,
+                        "Diagnostics" => SerializedItemKind::Diagnostics,
+                        "ProjectSearch" => SerializedItemKind::ProjectSearch,
+                        "Terminal" => SerializedItemKind::Terminal,
+                        _ => bail!("Stored serialized item kind is incorrect"),
+                    },
+                    next_index,
+                ))
+            })
+        }
+    }
+
+    #[derive(Debug, PartialEq, Eq, Clone)]
+    pub enum SerializedItem {
+        Editor { item_id: usize, path: Arc<Path> },
+        Diagnostics { item_id: usize },
+        ProjectSearch { item_id: usize, query: String },
+        Terminal { item_id: usize },
+    }
+
+    impl SerializedItem {
+        pub fn item_id(&self) -> usize {
+            match self {
+                SerializedItem::Editor { item_id, .. } => *item_id,
+                SerializedItem::Diagnostics { item_id } => *item_id,
+                SerializedItem::ProjectSearch { item_id, .. } => *item_id,
+                SerializedItem::Terminal { item_id } => *item_id,
+            }
+        }
+
+        pub(crate) fn kind(&self) -> SerializedItemKind {
+            match self {
+                SerializedItem::Editor { .. } => SerializedItemKind::Editor,
+                SerializedItem::Diagnostics { .. } => SerializedItemKind::Diagnostics,
+                SerializedItem::ProjectSearch { .. } => SerializedItemKind::ProjectSearch,
+                SerializedItem::Terminal { .. } => SerializedItemKind::Terminal,
+            }
+        }
+    }
+
+    #[cfg(test)]
+    mod tests {
+        use sqlez::connection::Connection;
+
+        use crate::model::DockAnchor;
+
+        use super::WorkspaceId;
+
+        #[test]
+        fn test_workspace_round_trips() {
+            let db = Connection::open_memory("workspace_id_round_trips");
+
+            db.exec(indoc::indoc! {"
+                CREATE TABLE workspace_id_test(
+                    workspace_id BLOB,
+                    dock_anchor TEXT
+                );"})
+                .unwrap()()
+            .unwrap();
+
+            let workspace_id: WorkspaceId = WorkspaceId::from(&["\test2", "\test1"]);
+
+            db.exec_bound("INSERT INTO workspace_id_test(workspace_id, dock_anchor) VALUES (?,?)")
+                .unwrap()((&workspace_id, DockAnchor::Bottom))
+            .unwrap();
+
+            assert_eq!(
+                db.select_row("SELECT workspace_id, dock_anchor FROM workspace_id_test LIMIT 1")
+                    .unwrap()()
+                .unwrap(),
+                Some((WorkspaceId::from(&["\test1", "\test2"]), DockAnchor::Bottom))
+            );
+        }
+    }
+}