Skip to content

Commit 08f59fa

Browse files
authored
Merge pull request #84 from powersync-ja/avoid-allocation-in-deserialize-to-i64
Avoid allocation in deserialize to i64
2 parents afb5da2 + a905e67 commit 08f59fa

File tree

1 file changed

+42
-13
lines changed

1 file changed

+42
-13
lines changed

crates/core/src/util.rs

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@ extern crate alloc;
33
use alloc::format;
44
use alloc::string::String;
55

6-
use serde::Deserialize;
7-
use serde_json as json;
8-
96
#[cfg(not(feature = "getrandom"))]
107
use crate::sqlite;
8+
use serde::de::Visitor;
119

1210
use uuid::Uuid;
1311

@@ -46,25 +44,56 @@ pub fn deserialize_string_to_i64<'de, D>(deserializer: D) -> Result<i64, D::Erro
4644
where
4745
D: serde::Deserializer<'de>,
4846
{
49-
let value = json::Value::deserialize(deserializer)?;
47+
struct ValueVisitor;
48+
49+
impl<'de> Visitor<'de> for ValueVisitor {
50+
type Value = i64;
51+
52+
fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
53+
formatter.write_str("a string representation of a number")
54+
}
5055

51-
match value {
52-
json::Value::String(s) => s.parse::<i64>().map_err(serde::de::Error::custom),
53-
_ => Err(serde::de::Error::custom("Expected a string.")),
56+
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
57+
where
58+
E: serde::de::Error,
59+
{
60+
v.parse::<i64>().map_err(serde::de::Error::custom)
61+
}
5462
}
63+
64+
// Using a custom visitor here to avoid an intermediate string allocation
65+
deserializer.deserialize_str(ValueVisitor)
5566
}
5667

5768
pub fn deserialize_optional_string_to_i64<'de, D>(deserializer: D) -> Result<Option<i64>, D::Error>
5869
where
5970
D: serde::Deserializer<'de>,
6071
{
61-
let value = json::Value::deserialize(deserializer)?;
62-
63-
match value {
64-
json::Value::Null => Ok(None),
65-
json::Value::String(s) => s.parse::<i64>().map(Some).map_err(serde::de::Error::custom),
66-
_ => Err(serde::de::Error::custom("Expected a string or null.")),
72+
struct ValueVisitor;
73+
74+
impl<'de> Visitor<'de> for ValueVisitor {
75+
type Value = Option<i64>;
76+
77+
fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
78+
formatter.write_str("a string or null")
79+
}
80+
81+
fn visit_none<E>(self) -> Result<Self::Value, E>
82+
where
83+
E: serde::de::Error,
84+
{
85+
Ok(None)
86+
}
87+
88+
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
89+
where
90+
D: serde::Deserializer<'de>,
91+
{
92+
Ok(Some(deserialize_string_to_i64(deserializer)?))
93+
}
6794
}
95+
96+
deserializer.deserialize_option(ValueVisitor)
6897
}
6998

7099
// Use getrandom crate to generate UUID.

0 commit comments

Comments
 (0)