Skip to content

Commit 7f900ea

Browse files
feat: serde support for a basic structs (#344)
* feat: serde support for a basic structs * cleanup
1 parent 208b382 commit 7f900ea

File tree

8 files changed

+159
-29
lines changed

8 files changed

+159
-29
lines changed

grovedb/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ tokio-util = { version = "0.7.12", optional = true }
3636
tokio = { version = "1.40.0", features = ["rt-multi-thread", "net"], optional = true }
3737
tower-http = { version = "0.5.2", features = ["fs"], optional = true }
3838
zip-extensions = { version ="0.6.2", optional = true }
39+
serde = { version = "1.0.210", features = ["derive"], optional = true }
3940

4041
[dev-dependencies]
4142
grovedb-epoch-based-storage-flags = { version = "2.1.0", path = "../grovedb-epoch-based-storage-flags" }
@@ -52,6 +53,7 @@ harness = false
5253
[features]
5354
default = ["full"]
5455
proof_debug = ["grovedb-merk/proof_debug"]
56+
serde = ["dep:serde", "grovedb-merk/serde", "indexmap/serde"]
5557
full = [
5658
"grovedb-merk/full",
5759
"thiserror",

grovedb/src/debugger.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ where
8585
let now = Instant::now();
8686
let mut lock = state.sessions.write().await;
8787
let to_delete: Vec<SessionId> = lock.iter().filter_map(
88-
|(id, session)| (session.last_access < now - SESSION_TIMEOUT).then_some(*id)
88+
|(id, session)|
89+
(session.last_access < now - SESSION_TIMEOUT).then_some(*id)
8990
).collect();
9091

9192
to_delete.into_iter().for_each(|id| { lock.remove(&id); });

grovedb/src/element/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ pub type SumValue = i64;
7171
/// of how serialization works.
7272
#[derive(Clone, Encode, Decode, PartialEq, Eq, Hash)]
7373
#[cfg_attr(not(any(feature = "full", feature = "visualize")), derive(Debug))]
74+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7475
pub enum Element {
7576
/// An ordinary value
7677
Item(Vec<u8>, Option<ElementFlags>),

grovedb/src/query/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use crate::Error;
2323

2424
#[cfg(any(feature = "full", feature = "verify"))]
2525
#[derive(Debug, Clone, PartialEq, Encode, Decode)]
26+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2627
/// Path query
2728
///
2829
/// Represents a path to a specific GroveDB tree and a corresponding query to
@@ -50,6 +51,7 @@ impl fmt::Display for PathQuery {
5051

5152
#[cfg(any(feature = "full", feature = "verify"))]
5253
#[derive(Debug, Clone, PartialEq, Encode, Decode)]
54+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
5355
/// Holds a query to apply to a tree and an optional limit/offset value.
5456
/// Limit and offset values affect the size of the result set.
5557
pub struct SizedQuery {

grovedb/src/reference_path.rs

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,3 @@
1-
// MIT LICENSE
2-
//
3-
// Copyright (c) 2021 Dash Core Group
4-
//
5-
// Permission is hereby granted, free of charge, to any
6-
// person obtaining a copy of this software and associated
7-
// documentation files (the "Software"), to deal in the
8-
// Software without restriction, including without
9-
// limitation the rights to use, copy, modify, merge,
10-
// publish, distribute, sublicense, and/or sell copies of
11-
// the Software, and to permit persons to whom the Software
12-
// is furnished to do so, subject to the following
13-
// conditions:
14-
//
15-
// The above copyright notice and this permission notice
16-
// shall be included in all copies or substantial portions
17-
// of the Software.
18-
//
19-
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
20-
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
21-
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
22-
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
23-
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24-
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25-
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
26-
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27-
// DEALINGS IN THE SOFTWARE.
28-
291
//! Space efficient methods for referencing other elements in GroveDB
302
313
#[cfg(any(feature = "full", feature = "verify"))]
@@ -42,6 +14,7 @@ use crate::Error;
4214

4315
#[cfg(any(feature = "full", feature = "verify"))]
4416
#[cfg_attr(not(any(feature = "full", feature = "visualize")), derive(Debug))]
17+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
4518
/// Reference path variants
4619
#[derive(Hash, Eq, PartialEq, Encode, Decode, Clone)]
4720
pub enum ReferencePathType {

merk/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ hex = "0.4.3"
2323
indexmap = "2.2.6"
2424
integer-encoding = "4.0.0"
2525
thiserror = "1.0.58"
26+
serde = { version = "1.0.210", features = ["derive"], optional = true }
2627

2728
[dependencies.time]
2829
version = "0.3.34"
@@ -56,6 +57,7 @@ optional = true
5657
[features]
5758
default = ["full"]
5859
proof_debug = []
60+
serde = ["dep:serde", "indexmap/serde"]
5961
full = ["rand",
6062
"time",
6163
"colored",

merk/src/proofs/query/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ pub type PathKey = (Path, Key);
6969

7070
#[cfg(any(feature = "full", feature = "verify"))]
7171
#[derive(Debug, Default, Clone, PartialEq, Encode, Decode)]
72+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7273
/// Subquery branch
7374
pub struct SubqueryBranch {
7475
/// Subquery path
@@ -111,6 +112,7 @@ impl SubqueryBranch {
111112
/// `Query` represents one or more keys or ranges of keys, which can be used to
112113
/// resolve a proof which will include all the requested values.
113114
#[derive(Debug, Default, Clone, PartialEq)]
115+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
114116
pub struct Query {
115117
/// Items
116118
pub items: Vec<QueryItem>,

merk/src/proofs/query/query_item/mod.rs

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ use bincode::{enc::write::Writer, error::DecodeError, BorrowDecode, Decode, Enco
1515
use grovedb_costs::{CostContext, CostsExt, OperationCost};
1616
#[cfg(feature = "full")]
1717
use grovedb_storage::RawIterator;
18+
#[cfg(feature = "serde")]
19+
use serde::de::VariantAccess;
20+
#[cfg(feature = "serde")]
21+
use serde::{Deserialize, Deserializer, Serialize, Serializer};
1822

1923
#[cfg(any(feature = "full", feature = "verify"))]
2024
use crate::error::Error;
@@ -36,6 +40,149 @@ pub enum QueryItem {
3640
RangeAfterToInclusive(RangeInclusive<Vec<u8>>),
3741
}
3842

43+
#[cfg(feature = "serde")]
44+
impl Serialize for QueryItem {
45+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
46+
where
47+
S: Serializer,
48+
{
49+
match self {
50+
QueryItem::Key(key) => serializer.serialize_newtype_variant("QueryItem", 0, "Key", key),
51+
QueryItem::Range(range) => {
52+
serializer.serialize_newtype_variant("QueryItem", 1, "Range", &range)
53+
}
54+
QueryItem::RangeInclusive(range) => {
55+
serializer.serialize_newtype_variant("QueryItem", 2, "RangeInclusive", range)
56+
}
57+
QueryItem::RangeFull(_) => {
58+
serializer.serialize_unit_variant("QueryItem", 3, "RangeFull")
59+
}
60+
QueryItem::RangeFrom(range_from) => {
61+
serializer.serialize_newtype_variant("QueryItem", 4, "RangeFrom", range_from)
62+
}
63+
QueryItem::RangeTo(range_to) => {
64+
serializer.serialize_newtype_variant("QueryItem", 5, "RangeTo", range_to)
65+
}
66+
QueryItem::RangeToInclusive(range_to_inclusive) => serializer
67+
.serialize_newtype_variant(
68+
"QueryItem",
69+
6,
70+
"RangeToInclusive",
71+
&range_to_inclusive.end,
72+
),
73+
QueryItem::RangeAfter(range_after) => {
74+
serializer.serialize_newtype_variant("QueryItem", 7, "RangeAfter", range_after)
75+
}
76+
QueryItem::RangeAfterTo(range_after_to) => {
77+
serializer.serialize_newtype_variant("QueryItem", 8, "RangeAfterTo", range_after_to)
78+
}
79+
QueryItem::RangeAfterToInclusive(range_after_to_inclusive) => serializer
80+
.serialize_newtype_variant(
81+
"QueryItem",
82+
9,
83+
"RangeAfterToInclusive",
84+
range_after_to_inclusive,
85+
),
86+
}
87+
}
88+
}
89+
90+
#[cfg(feature = "serde")]
91+
impl<'de> Deserialize<'de> for QueryItem {
92+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
93+
where
94+
D: Deserializer<'de>,
95+
{
96+
#[derive(Deserialize)]
97+
#[serde(field_identifier, rename_all = "snake_case")]
98+
enum Field {
99+
Key,
100+
Range,
101+
RangeInclusive,
102+
RangeFull,
103+
RangeFrom,
104+
RangeTo,
105+
RangeToInclusive,
106+
RangeAfter,
107+
RangeAfterTo,
108+
RangeAfterToInclusive,
109+
}
110+
111+
struct QueryItemVisitor;
112+
113+
impl<'de> serde::de::Visitor<'de> for QueryItemVisitor {
114+
type Value = QueryItem;
115+
116+
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
117+
formatter.write_str("enum QueryItem")
118+
}
119+
120+
fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
121+
where
122+
A: serde::de::EnumAccess<'de>,
123+
{
124+
let (variant, variant_access) = data.variant()?;
125+
126+
match variant {
127+
Field::Key => {
128+
let key = variant_access.newtype_variant()?;
129+
Ok(QueryItem::Key(key))
130+
}
131+
Field::Range => {
132+
let range = variant_access.newtype_variant()?;
133+
Ok(QueryItem::Range(range))
134+
}
135+
Field::RangeInclusive => {
136+
let range_inclusive = variant_access.newtype_variant()?;
137+
Ok(QueryItem::RangeInclusive(range_inclusive))
138+
}
139+
Field::RangeFull => Ok(QueryItem::RangeFull(RangeFull)),
140+
Field::RangeFrom => {
141+
let range_from = variant_access.newtype_variant()?;
142+
Ok(QueryItem::RangeFrom(range_from))
143+
}
144+
Field::RangeTo => {
145+
let range_to = variant_access.newtype_variant()?;
146+
Ok(QueryItem::RangeTo(range_to))
147+
}
148+
Field::RangeToInclusive => {
149+
// Deserialize the `Vec<u8>` for the `end` of the range
150+
let end = variant_access.newtype_variant()?;
151+
Ok(QueryItem::RangeToInclusive(..=end))
152+
}
153+
Field::RangeAfter => {
154+
let range_after = variant_access.newtype_variant()?;
155+
Ok(QueryItem::RangeAfter(range_after))
156+
}
157+
Field::RangeAfterTo => {
158+
let range_after_to = variant_access.newtype_variant()?;
159+
Ok(QueryItem::RangeAfterTo(range_after_to))
160+
}
161+
Field::RangeAfterToInclusive => {
162+
let range_after_to_inclusive = variant_access.newtype_variant()?;
163+
Ok(QueryItem::RangeAfterToInclusive(range_after_to_inclusive))
164+
}
165+
}
166+
}
167+
}
168+
169+
const VARIANTS: &[&str] = &[
170+
"Key",
171+
"Range",
172+
"RangeInclusive",
173+
"RangeFull",
174+
"RangeFrom",
175+
"RangeTo",
176+
"RangeToInclusive",
177+
"RangeAfter",
178+
"RangeAfterTo",
179+
"RangeAfterToInclusive",
180+
];
181+
182+
deserializer.deserialize_enum("QueryItem", VARIANTS, QueryItemVisitor)
183+
}
184+
}
185+
39186
#[cfg(any(feature = "full", feature = "verify"))]
40187
impl Encode for QueryItem {
41188
fn encode<E: bincode::enc::Encoder>(

0 commit comments

Comments
 (0)