diff --git a/lsp-positions/Cargo.toml b/lsp-positions/Cargo.toml index 1b2d6776e..2b2d496b3 100644 --- a/lsp-positions/Cargo.toml +++ b/lsp-positions/Cargo.toml @@ -18,9 +18,11 @@ test = false [features] default = ["tree-sitter"] +bincode = ["dep:bincode"] [dependencies] memchr = "2.4" tree-sitter = { version=">= 0.19", optional=true } unicode-segmentation = { version="1.8" } serde = { version="1", optional=true, features=["derive"] } +bincode = { version="2.0.0-rc.3", optional=true } diff --git a/lsp-positions/src/lib.rs b/lsp-positions/src/lib.rs index f990a2a15..628cec2a7 100644 --- a/lsp-positions/src/lib.rs +++ b/lsp-positions/src/lib.rs @@ -45,6 +45,7 @@ fn utf16_len(string: &str) -> usize { #[repr(C)] #[derive(Clone, Debug, Default, Eq, Hash, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))] pub struct Position { /// The 0-indexed line number containing the character pub line: usize, @@ -108,6 +109,7 @@ impl PartialOrd for Position { #[repr(C)] #[derive(Clone, Debug, Default, Eq, Hash, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))] pub struct Span { pub start: Position, pub end: Position, @@ -144,6 +146,7 @@ impl PartialOrd for Span { /// All offsets are 0-indexed. #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))] pub struct Offset { /// The number of UTF-8-encoded bytes appearing before this character in the string pub utf8_offset: usize, diff --git a/stack-graphs/Cargo.toml b/stack-graphs/Cargo.toml index 9e6870ed7..e283e25f6 100644 --- a/stack-graphs/Cargo.toml +++ b/stack-graphs/Cargo.toml @@ -13,9 +13,10 @@ authors = [ edition = "2018" [features] +bincode = ["dep:bincode", "lsp-positions/bincode"] copious-debugging = [] -serde = ["dep:serde", "lsp-positions/serde"] -storage = ["postcard", "rusqlite", "serde"] +serde = ["dep:serde", "serde_with", "lsp-positions/serde"] +storage = ["bincode", "rusqlite"] visualization = ["serde", "serde_json"] [lib] @@ -23,6 +24,7 @@ visualization = ["serde", "serde_json"] test = false [dependencies] +bincode = { version = "2.0.0-rc.3", optional = true } bitvec = "1.0" controlled-option = "0.4" either = "1.6" @@ -31,10 +33,10 @@ fxhash = "0.2" itertools = "0.10" libc = "0.2" lsp-positions = { version = "0.3", path = "../lsp-positions" } -postcard = { version = "1", optional = true, features = ["use-std"] } rusqlite = { version = "0.28", optional = true, features = ["bundled", "functions"] } serde = { version = "1.0", optional = true, features = ["derive"] } serde_json = { version = "1.0", optional = true } +serde_with = { version = "3.1", optional = true } smallvec = { version = "1.6", features = ["union"] } thiserror = { version = "1.0" } diff --git a/stack-graphs/src/lib.rs b/stack-graphs/src/lib.rs index 3ef344b8f..009076af9 100644 --- a/stack-graphs/src/lib.rs +++ b/stack-graphs/src/lib.rs @@ -68,7 +68,6 @@ mod debugging; pub mod graph; pub mod partial; pub mod paths; -#[cfg(feature = "serde")] pub mod serde; pub mod stitching; #[cfg(feature = "storage")] diff --git a/stack-graphs/src/serde/graph.rs b/stack-graphs/src/serde/graph.rs index 263441414..6cb06744a 100644 --- a/stack-graphs/src/serde/graph.rs +++ b/stack-graphs/src/serde/graph.rs @@ -5,8 +5,6 @@ // Please see the LICENSE-APACHE or LICENSE-MIT files in this distribution for license details. // ------------------------------------------------------------------------------------------------ -use serde::Deserialize; -use serde::Serialize; use thiserror::Error; use crate::arena::Handle; @@ -15,7 +13,9 @@ use super::Filter; use super::ImplicationFilter; use super::NoFilter; -#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Default, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))] pub struct StackGraph { pub files: Files, pub nodes: Nodes, @@ -202,34 +202,46 @@ impl StackGraph { } } -#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] -#[serde(transparent)] +#[derive(Clone, Debug, Default, Eq, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Deserialize, serde::Serialize), + serde(transparent) +)] +#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))] pub struct Files { pub data: Vec, } -#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] -#[serde(transparent)] +#[derive(Clone, Debug, Default, Eq, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Deserialize, serde::Serialize), + serde(transparent) +)] +#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))] pub struct Nodes { pub data: Vec, } -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] -#[serde(tag = "type", rename_all = "snake_case")] +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr( + feature = "serde", + serde_with::skip_serializing_none, // must come before derive + derive(serde::Deserialize, serde::Serialize), + serde(tag = "type", rename_all = "snake_case"), +)] +#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))] pub enum Node { DropScopes { id: NodeID, - #[serde(skip_serializing_if = "Option::is_none")] source_info: Option, - #[serde(skip_serializing_if = "Option::is_none")] debug_info: Option, }, JumpToScope { id: NodeID, - #[serde(skip_serializing_if = "Option::is_none")] source_info: Option, - #[serde(skip_serializing_if = "Option::is_none")] debug_info: Option, }, @@ -237,9 +249,7 @@ pub enum Node { id: NodeID, symbol: String, is_definition: bool, - #[serde(skip_serializing_if = "Option::is_none")] source_info: Option, - #[serde(skip_serializing_if = "Option::is_none")] debug_info: Option, }, @@ -247,9 +257,7 @@ pub enum Node { id: NodeID, symbol: String, is_definition: bool, - #[serde(skip_serializing_if = "Option::is_none")] source_info: Option, - #[serde(skip_serializing_if = "Option::is_none")] debug_info: Option, }, @@ -258,9 +266,7 @@ pub enum Node { symbol: String, scope: NodeID, is_reference: bool, - #[serde(skip_serializing_if = "Option::is_none")] source_info: Option, - #[serde(skip_serializing_if = "Option::is_none")] debug_info: Option, }, @@ -268,26 +274,20 @@ pub enum Node { id: NodeID, symbol: String, is_reference: bool, - #[serde(skip_serializing_if = "Option::is_none")] source_info: Option, - #[serde(skip_serializing_if = "Option::is_none")] debug_info: Option, }, Root { id: NodeID, - #[serde(skip_serializing_if = "Option::is_none")] source_info: Option, - #[serde(skip_serializing_if = "Option::is_none")] debug_info: Option, }, Scope { id: NodeID, is_exported: bool, - #[serde(skip_serializing_if = "Option::is_none")] source_info: Option, - #[serde(skip_serializing_if = "Option::is_none")] debug_info: Option, }, } @@ -322,28 +322,45 @@ impl Node { } } -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr( + feature = "serde", + serde_with::skip_serializing_none, // must come before derive + derive(serde::Deserialize, serde::Serialize), +)] +#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))] pub struct SourceInfo { pub span: lsp_positions::Span, - #[serde(skip_serializing_if = "Option::is_none")] pub syntax_type: Option, } -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] -#[serde(transparent)] +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Deserialize, serde::Serialize), + serde(transparent) +)] +#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))] pub struct DebugInfo { pub data: Vec, } -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))] pub struct DebugEntry { pub key: String, pub value: String, } -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr( + feature = "serde", + serde_with::skip_serializing_none, // must come before derive + derive(serde::Deserialize, serde::Serialize), +)] +#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))] pub struct NodeID { - #[serde(skip_serializing_if = "Option::is_none")] pub file: Option, pub local_id: u32, } @@ -398,18 +415,28 @@ impl std::fmt::Display for NodeID { } } -#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] -#[serde(transparent)] +#[derive(Clone, Debug, Default, Eq, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Deserialize, serde::Serialize), + serde(transparent) +)] +#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))] pub struct Edges { pub data: Vec, } -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr( + feature = "serde", + serde_with::skip_serializing_none, // must come before derive + derive(serde::Deserialize, serde::Serialize), +)] +#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))] pub struct Edge { pub source: NodeID, pub sink: NodeID, pub precedence: i32, - #[serde(skip_serializing_if = "Option::is_none")] pub debug_info: Option, } diff --git a/stack-graphs/src/serde/partial.rs b/stack-graphs/src/serde/partial.rs index 095041415..f9ca16d77 100644 --- a/stack-graphs/src/serde/partial.rs +++ b/stack-graphs/src/serde/partial.rs @@ -5,15 +5,14 @@ // Please see the LICENSE-APACHE or LICENSE-MIT files in this distribution for license details. // ------------------------------------------------------------------------------------------------ -use serde::Deserialize; -use serde::Serialize; - use crate::partial::PartialPaths; use super::Error; use super::NodeID; -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))] pub struct PartialPath { pub(crate) start_node: NodeID, pub(crate) end_node: NodeID, @@ -82,10 +81,15 @@ impl PartialPath { } } -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr( + feature = "serde", + serde_with::skip_serializing_none, // must come before derive + derive(serde::Deserialize, serde::Serialize), +)] +#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))] pub struct PartialScopeStack { pub(crate) scopes: Vec, - #[serde(skip_serializing_if = "Option::is_none")] variable: Option, } @@ -127,8 +131,13 @@ impl PartialScopeStack { } } -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] -#[serde(transparent)] +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Deserialize, serde::Serialize), + serde(transparent) +)] +#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))] pub struct ScopeStackVariable(u32); impl ScopeStackVariable { @@ -142,10 +151,15 @@ impl ScopeStackVariable { } } -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr( + feature = "serde", + serde_with::skip_serializing_none, // must come before derive + derive(serde::Deserialize, serde::Serialize), +)] +#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))] pub struct PartialSymbolStack { pub(crate) symbols: Vec, - #[serde(skip_serializing_if = "Option::is_none")] variable: Option, } @@ -189,8 +203,13 @@ impl PartialSymbolStack { } } -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] -#[serde(transparent)] +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Deserialize, serde::Serialize), + serde(transparent) +)] +#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))] pub struct SymbolStackVariable(u32); impl SymbolStackVariable { @@ -204,10 +223,15 @@ impl SymbolStackVariable { } } -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr( + feature = "serde", + serde_with::skip_serializing_none, // must come before derive + derive(serde::Deserialize, serde::Serialize), +)] +#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))] pub struct PartialScopedSymbol { symbol: String, - #[serde(skip_serializing_if = "Option::is_none")] pub(crate) scopes: Option, } @@ -242,8 +266,13 @@ impl PartialScopedSymbol { } } -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] -#[serde(transparent)] +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde::Deserialize, serde::Serialize), + serde(transparent) +)] +#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))] pub struct PartialPathEdgeList { pub(crate) edges: Vec, } @@ -278,7 +307,9 @@ impl PartialPathEdgeList { } } -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))] pub struct PartialPathEdge { pub(crate) source: NodeID, precedence: i32, diff --git a/stack-graphs/src/serde/stitching.rs b/stack-graphs/src/serde/stitching.rs index 124f17dba..0de6eff48 100644 --- a/stack-graphs/src/serde/stitching.rs +++ b/stack-graphs/src/serde/stitching.rs @@ -5,9 +5,6 @@ // Please see the LICENSE-APACHE or LICENSE-MIT files in this distribution for license details. // ------------------------------------------------------------------------------------------------ -use serde::Deserialize; -use serde::Serialize; - use crate::graph::StackGraph; use crate::partial::PartialPaths; @@ -17,8 +14,12 @@ use super::ImplicationFilter; use super::NoFilter; use super::PartialPath; -#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] -#[serde(transparent)] +#[derive(PartialEq, Eq, Debug, Clone)] +#[cfg_attr( + feature = "serde", + derive(serde::Deserialize, serde::Serialize), + serde(transparent) +)] pub struct Database { paths: Vec, } diff --git a/stack-graphs/src/storage.rs b/stack-graphs/src/storage.rs index 1b46ba92f..ee39c457e 100644 --- a/stack-graphs/src/storage.rs +++ b/stack-graphs/src/storage.rs @@ -5,6 +5,8 @@ // Please see the LICENSE-APACHE or LICENSE-MIT files in this distribution for license details. // ------------------------------------------------------------------------------------------------ +use bincode::error::DecodeError; +use bincode::error::EncodeError; use rusqlite::functions::FunctionFlags; use rusqlite::types::ValueRef; use rusqlite::Connection; @@ -30,7 +32,7 @@ use crate::stitching::ForwardPartialPathStitcher; use crate::CancellationError; use crate::CancellationFlag; -const VERSION: usize = 4; +const VERSION: usize = 5; const SCHEMA: &str = r#" CREATE TABLE metadata ( @@ -62,6 +64,8 @@ const PRAGMAS: &str = r#" PRAGMA secure_delete = false; "#; +pub static BINCODE_CONFIG: bincode::config::Configuration = bincode::config::standard(); + #[derive(Debug, Error)] pub enum StorageError { #[error("cancelled at {0}")] @@ -75,7 +79,9 @@ pub enum StorageError { #[error(transparent)] Serde(#[from] serde::Error), #[error(transparent)] - PostcardError(#[from] postcard::Error), + SerializeFail(#[from] EncodeError), + #[error(transparent)] + DeserializeFail(#[from] DecodeError), } pub type Result = std::result::Result; @@ -277,12 +283,8 @@ impl SQLiteWriter { let mut stmt = conn .prepare_cached("INSERT INTO graphs (file, tag, error, value) VALUES (?, ?, ?, ?)")?; let graph = crate::serde::StackGraph::default(); - stmt.execute(( - &file.to_string_lossy(), - tag, - error, - &postcard::to_stdvec(&graph)?, - ))?; + let serialized = bincode::encode_to_vec(&graph, BINCODE_CONFIG)?; + stmt.execute((&file.to_string_lossy(), tag, error, serialized))?; Ok(()) } @@ -321,7 +323,8 @@ impl SQLiteWriter { let mut stmt = conn.prepare_cached("INSERT INTO graphs (file, tag, value) VALUES (?, ?, ?)")?; let graph = serde::StackGraph::from_graph_filter(graph, &FileFilter(file)); - stmt.execute((file_str, tag, &postcard::to_stdvec(&graph)?))?; + let serialized = bincode::encode_to_vec(&graph, BINCODE_CONFIG)?; + stmt.execute((file_str, tag, &serialized))?; Ok(()) } @@ -362,7 +365,8 @@ impl SQLiteWriter { ); let symbol_stack = path.symbol_stack_precondition.storage_key(graph, partials); let path = serde::PartialPath::from_partial_path(graph, partials, path); - root_stmt.execute((file_str, symbol_stack, &postcard::to_stdvec(&path)?))?; + let serialized = bincode::encode_to_vec(&path, BINCODE_CONFIG)?; + root_stmt.execute((file_str, symbol_stack, serialized))?; root_path_count += 1; } else if start_node.is_in_file(file) { copious_debugging!( @@ -370,11 +374,8 @@ impl SQLiteWriter { path.start_node.display(graph), ); let path = serde::PartialPath::from_partial_path(graph, partials, path); - node_stmt.execute(( - file_str, - path.start_node.local_id, - &postcard::to_stdvec(&path)?, - ))?; + let serialized = bincode::encode_to_vec(&path, BINCODE_CONFIG)?; + node_stmt.execute((file_str, path.start_node.local_id, serialized))?; node_path_count += 1; } else { panic!( @@ -523,7 +524,8 @@ impl SQLiteReader { copious_debugging!(" * Load from database"); let mut stmt = conn.prepare_cached("SELECT value FROM graphs WHERE file = ?")?; let value = stmt.query_row([file], |row| row.get::<_, Vec>(0))?; - let file_graph = postcard::from_bytes::(&value)?; + let (file_graph, _): (serde::StackGraph, usize) = + bincode::decode_from_slice(&value, BINCODE_CONFIG)?; file_graph.load_into(graph)?; Ok(graph.get_file(file).expect("loaded file to exist")) } @@ -579,7 +581,8 @@ impl SQLiteReader { &mut self.loaded_graphs, &self.conn, )?; - let path = postcard::from_bytes::(&value)?; + let (path, _): (serde::PartialPath, usize) = + bincode::decode_from_slice(&value, BINCODE_CONFIG)?; let path = path.to_partial_path(&mut self.graph, &mut self.partials)?; copious_debugging!( " > Loaded {}", @@ -633,7 +636,8 @@ impl SQLiteReader { &mut self.loaded_graphs, &self.conn, )?; - let path = postcard::from_bytes::(&value)?; + let (path, _): (serde::PartialPath, usize) = + bincode::decode_from_slice(&value, BINCODE_CONFIG)?; let path = path.to_partial_path(&mut self.graph, &mut self.partials)?; copious_debugging!( " > Loaded {}",