Skip to content

Commit b1c15a2

Browse files
authored
Merge pull request #61 from sundy-li/lazy-value
feat: add lazy value
2 parents 86a260c + 22f324c commit b1c15a2

File tree

5 files changed

+99
-3
lines changed

5 files changed

+99
-3
lines changed

src/functions.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2619,7 +2619,7 @@ pub fn type_of(value: &[u8]) -> Result<&'static str, Error> {
26192619

26202620
// Check whether the value is `JSONB` format,
26212621
// for compatibility with previous `JSON` string.
2622-
fn is_jsonb(value: &[u8]) -> bool {
2622+
pub(crate) fn is_jsonb(value: &[u8]) -> bool {
26232623
if let Some(v) = value.first() {
26242624
if matches!(*v, ARRAY_PREFIX | OBJECT_PREFIX | SCALAR_PREFIX) {
26252625
return true;

src/lazy_value.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Copyright 2023 Datafuse Labs.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
use std::borrow::Cow;
16+
use std::fmt::Debug;
17+
18+
use crate::array_length;
19+
use crate::ser::Encoder;
20+
use crate::Value;
21+
22+
#[derive(Debug, Clone, PartialEq, Eq)]
23+
pub enum LazyValue<'a> {
24+
Value(Value<'a>),
25+
// Raw JSONB bytes
26+
Raw(Cow<'a, [u8]>),
27+
}
28+
29+
impl<'a> LazyValue<'a> {
30+
/// Serialize the JSONB Value into a byte stream.
31+
pub fn write_to_vec(&self, buf: &mut Vec<u8>) {
32+
match self {
33+
LazyValue::Value(v) => {
34+
let mut encoder = Encoder::new(buf);
35+
encoder.encode(v)
36+
}
37+
LazyValue::Raw(v) => buf.extend_from_slice(v),
38+
};
39+
}
40+
41+
/// Serialize the JSONB Value into a byte stream.
42+
pub fn to_vec(&self) -> Vec<u8> {
43+
match self {
44+
LazyValue::Value(value) => {
45+
let mut buf = Vec::new();
46+
value.write_to_vec(&mut buf);
47+
buf
48+
}
49+
LazyValue::Raw(cow) => cow.to_vec(),
50+
}
51+
}
52+
53+
// TODO migrate more functions to be methods of LazyValue
54+
pub fn array_length(&self) -> Option<usize> {
55+
match self {
56+
LazyValue::Value(Value::Array(arr)) => Some(arr.len()),
57+
LazyValue::Raw(cow) => array_length(cow.as_ref()),
58+
_ => None,
59+
}
60+
}
61+
62+
pub fn to_value(&'a self) -> Cow<Value<'a>> {
63+
match self {
64+
LazyValue::Value(v) => Cow::Borrowed(v),
65+
LazyValue::Raw(v) => Cow::Owned(crate::from_slice(v.as_ref()).unwrap()),
66+
}
67+
}
68+
}
69+
70+
impl<'a> From<Value<'a>> for LazyValue<'a> {
71+
fn from(value: Value<'a>) -> Self {
72+
LazyValue::Value(value)
73+
}
74+
}

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ mod iterator;
7373
mod jentry;
7474
pub mod jsonpath;
7575
pub mod keypath;
76+
mod lazy_value;
7677
mod number;
7778
mod parser;
7879
mod ser;
@@ -84,6 +85,8 @@ pub use error::Error;
8485
#[allow(unused_imports)]
8586
pub use from::*;
8687
pub use functions::*;
88+
pub use lazy_value::*;
8789
pub use number::Number;
90+
pub use parser::parse_lazy_value;
8891
pub use parser::parse_value;
8992
pub use value::*;

src/parser.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414

1515
use std::borrow::Cow;
1616

17+
use crate::is_jsonb;
18+
use crate::lazy_value::LazyValue;
19+
1720
use super::constants::*;
1821
use super::error::Error;
1922
use super::error::ParseErrorCode;
@@ -30,6 +33,14 @@ pub fn parse_value(buf: &[u8]) -> Result<Value<'_>, Error> {
3033
parser.parse()
3134
}
3235

36+
pub fn parse_lazy_value(buf: &[u8]) -> Result<LazyValue<'_>, Error> {
37+
if !is_jsonb(buf) {
38+
parse_value(buf).map(LazyValue::Value)
39+
} else {
40+
Ok(LazyValue::Raw(Cow::Borrowed(buf)))
41+
}
42+
}
43+
3344
struct Parser<'a> {
3445
buf: &'a [u8],
3546
idx: usize,

tests/it/encode.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
use std::borrow::Cow;
1616

17-
use jsonb::{Number, Object, Value};
17+
use jsonb::{parse_lazy_value, Number, Object, Value};
1818

1919
#[test]
2020
fn test_encode_null() {
@@ -133,9 +133,17 @@ fn test_encode_float64() {
133133

134134
#[test]
135135
fn test_encode_array() {
136+
let raw = b"\x80\0\0\x02\x30\0\0\0\x40\0\0\0";
136137
assert_eq!(
137138
&Value::Array(vec![Value::Bool(false), Value::Bool(true)]).to_vec(),
138-
b"\x80\0\0\x02\x30\0\0\0\x40\0\0\0"
139+
raw
140+
);
141+
142+
let lazy_value = parse_lazy_value(raw).unwrap();
143+
assert_eq!(lazy_value.array_length(), Some(2));
144+
assert_eq!(
145+
lazy_value.to_value().as_ref(),
146+
&Value::Array(vec![Value::Bool(false), Value::Bool(true)])
139147
);
140148
}
141149

0 commit comments

Comments
 (0)