Skip to content

Commit

Permalink
Merge pull request #61 from sundy-li/lazy-value
Browse files Browse the repository at this point in the history
feat: add lazy value
  • Loading branch information
b41sh authored Oct 9, 2024
2 parents 86a260c + 22f324c commit b1c15a2
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 3 deletions.
2 changes: 1 addition & 1 deletion src/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2619,7 +2619,7 @@ pub fn type_of(value: &[u8]) -> Result<&'static str, Error> {

// Check whether the value is `JSONB` format,
// for compatibility with previous `JSON` string.
fn is_jsonb(value: &[u8]) -> bool {
pub(crate) fn is_jsonb(value: &[u8]) -> bool {
if let Some(v) = value.first() {
if matches!(*v, ARRAY_PREFIX | OBJECT_PREFIX | SCALAR_PREFIX) {
return true;
Expand Down
74 changes: 74 additions & 0 deletions src/lazy_value.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright 2023 Datafuse Labs.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::borrow::Cow;
use std::fmt::Debug;

use crate::array_length;
use crate::ser::Encoder;
use crate::Value;

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum LazyValue<'a> {
Value(Value<'a>),
// Raw JSONB bytes
Raw(Cow<'a, [u8]>),
}

impl<'a> LazyValue<'a> {
/// Serialize the JSONB Value into a byte stream.
pub fn write_to_vec(&self, buf: &mut Vec<u8>) {
match self {
LazyValue::Value(v) => {
let mut encoder = Encoder::new(buf);
encoder.encode(v)
}
LazyValue::Raw(v) => buf.extend_from_slice(v),
};
}

/// Serialize the JSONB Value into a byte stream.
pub fn to_vec(&self) -> Vec<u8> {
match self {
LazyValue::Value(value) => {
let mut buf = Vec::new();
value.write_to_vec(&mut buf);
buf
}
LazyValue::Raw(cow) => cow.to_vec(),
}
}

// TODO migrate more functions to be methods of LazyValue
pub fn array_length(&self) -> Option<usize> {
match self {
LazyValue::Value(Value::Array(arr)) => Some(arr.len()),
LazyValue::Raw(cow) => array_length(cow.as_ref()),
_ => None,
}
}

pub fn to_value(&'a self) -> Cow<Value<'a>> {
match self {
LazyValue::Value(v) => Cow::Borrowed(v),
LazyValue::Raw(v) => Cow::Owned(crate::from_slice(v.as_ref()).unwrap()),
}
}
}

impl<'a> From<Value<'a>> for LazyValue<'a> {
fn from(value: Value<'a>) -> Self {
LazyValue::Value(value)
}
}
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ mod iterator;
mod jentry;
pub mod jsonpath;
pub mod keypath;
mod lazy_value;
mod number;
mod parser;
mod ser;
Expand All @@ -84,6 +85,8 @@ pub use error::Error;
#[allow(unused_imports)]
pub use from::*;
pub use functions::*;
pub use lazy_value::*;
pub use number::Number;
pub use parser::parse_lazy_value;
pub use parser::parse_value;
pub use value::*;
11 changes: 11 additions & 0 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@

use std::borrow::Cow;

use crate::is_jsonb;
use crate::lazy_value::LazyValue;

use super::constants::*;
use super::error::Error;
use super::error::ParseErrorCode;
Expand All @@ -30,6 +33,14 @@ pub fn parse_value(buf: &[u8]) -> Result<Value<'_>, Error> {
parser.parse()
}

pub fn parse_lazy_value(buf: &[u8]) -> Result<LazyValue<'_>, Error> {
if !is_jsonb(buf) {
parse_value(buf).map(LazyValue::Value)
} else {
Ok(LazyValue::Raw(Cow::Borrowed(buf)))
}
}

struct Parser<'a> {
buf: &'a [u8],
idx: usize,
Expand Down
12 changes: 10 additions & 2 deletions tests/it/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

use std::borrow::Cow;

use jsonb::{Number, Object, Value};
use jsonb::{parse_lazy_value, Number, Object, Value};

#[test]
fn test_encode_null() {
Expand Down Expand Up @@ -133,9 +133,17 @@ fn test_encode_float64() {

#[test]
fn test_encode_array() {
let raw = b"\x80\0\0\x02\x30\0\0\0\x40\0\0\0";
assert_eq!(
&Value::Array(vec![Value::Bool(false), Value::Bool(true)]).to_vec(),
b"\x80\0\0\x02\x30\0\0\0\x40\0\0\0"
raw
);

let lazy_value = parse_lazy_value(raw).unwrap();
assert_eq!(lazy_value.array_length(), Some(2));
assert_eq!(
lazy_value.to_value().as_ref(),
&Value::Array(vec![Value::Bool(false), Value::Bool(true)])
);
}

Expand Down

0 comments on commit b1c15a2

Please sign in to comment.