Skip to content

Commit

Permalink
deer: switch to justjson (#2444)
Browse files Browse the repository at this point in the history
* feat: nuke old version

* feat: init deserializer

* feat: error

* feat: parse number

* feat: deserialize more tokens

* feat: deserialize more

* fix: ref

* chore: yoink from #2437

* feat: adapt `skip_tokens` for `justjson`

* chore: imports

* feat: create `ObjectAccess`

* fix: compile

* feat: recursion limit

* feat: recursion limit grace

* feat: deserialize colon

* feat: deserialize array

* feat: deserialize struct

* feat: deserialize enum

* fix: clippy

* chore: remove comments

* chore: temporary fix

* fix: clippy

* feat: implement `deserialize_identifier`

* feat: pub `StackLimit`
  • Loading branch information
indietyp authored Jun 6, 2023
1 parent 647833e commit 3ed367d
Show file tree
Hide file tree
Showing 15 changed files with 1,211 additions and 715 deletions.
13 changes: 3 additions & 10 deletions libs/deer/desert/src/array.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use deer::{
error::{ArrayAccessError, ArrayLengthError, ExpectedLength, ReceivedLength, Variant},
error::{ArrayAccessError, ArrayLengthError},
Context, Deserialize, Deserializer as _,
};
use error_stack::{Report, Result, ResultExt};
use error_stack::{Result, ResultExt};

use crate::{deserializer::Deserializer, skip::skip_tokens, token::Token};

Expand Down Expand Up @@ -59,14 +59,7 @@ impl<'de> deer::ArrayAccess<'de> for ArrayAccess<'_, '_, 'de> {
let result = if self.deserializer.peek() == Token::ArrayEnd {
Ok(())
} else {
let mut error = Report::new(ArrayLengthError.into_error())
.attach(ExpectedLength::new(self.expected));

if let Some(length) = self.size_hint() {
error = error.attach(ReceivedLength::new(length));
}

Err(error)
Err(ArrayLengthError::new(&self, self.expected))
};

// bump until the very end, which ensures that deserialize calls after this might succeed!
Expand Down
13 changes: 3 additions & 10 deletions libs/deer/desert/src/object.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use deer::{
error::{ExpectedLength, ObjectAccessError, ObjectLengthError, ReceivedLength, Variant},
error::{ObjectAccessError, ObjectLengthError},
Context, Deserializer as _, FieldVisitor,
};
use error_stack::{Report, Result, ResultExt};
use error_stack::{Result, ResultExt};

use crate::{deserializer::Deserializer, skip::skip_tokens, token::Token};

Expand Down Expand Up @@ -72,14 +72,7 @@ impl<'de> deer::ObjectAccess<'de> for ObjectAccess<'_, '_, 'de> {
let result = if self.deserializer.peek() == Token::ObjectEnd {
Ok(())
} else {
let mut error = Report::new(ObjectLengthError.into_error())
.attach(ExpectedLength::new(self.expected));

if let Some(length) = self.size_hint() {
error = error.attach(ReceivedLength::new(length));
}

Err(error)
Err(ObjectLengthError::new(&self, self.expected))
};

// bump until the very end, which ensures that deserialize calls after this might succeed!
Expand Down
12 changes: 7 additions & 5 deletions libs/deer/json/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ publish = false
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
error-stack = { version = "0.3.1", default_features = false }
error-stack = { version = "0.3.1", default-features = false }

serde_json = { version = "1.0.96", default_features = false, features = ['alloc'] }
deer = { path = "..", default-features = false }

deer = { path = "..", default_features = false }
justjson = { version = "0.2.3", default-features = false, features = ['alloc'] }
lexical = { version = "6.1.1", default-features = false, features = ['parse-floats', 'parse-integers', 'format'] }
memchr = "2.5.0"

[features]
default = ['std']
std = ["serde_json/std", "deer/std"]
arbitrary-precision = ['deer/arbitrary-precision', 'serde_json/arbitrary_precision']
std = ["justjson/std", "deer/std"]
arbitrary-precision = ['deer/arbitrary-precision']
102 changes: 102 additions & 0 deletions libs/deer/json/src/array.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
use deer::{
error::{ArrayAccessError, ArrayLengthError, DeserializerError, Error, Variant},
Context, Deserialize, Deserializer as _,
};
use error_stack::{Report, Result, ResultExt};
use justjson::parser::{PeekableTokenKind, Token};

use crate::{
deserializer::Deserializer,
error::{ErrorAccumulator, Position, SyntaxError},
skip::skip_tokens,
};

pub(crate) struct ArrayAccess<'a, 'b, 'de: 'a> {
deserializer: &'a mut Deserializer<'b, 'de>,

dirty: bool,
expected: usize,
}

impl<'a, 'b, 'de: 'a> ArrayAccess<'a, 'b, 'de> {
pub(crate) fn new(
deserializer: &'a mut Deserializer<'b, 'de>,
) -> Result<Self, DeserializerError> {
deserializer.try_stack_push(&Token::Array)?;

Ok(Self {
deserializer,
dirty: false,
expected: 0,
})
}

fn try_skip_comma(&mut self) -> Result<(), Error> {
self.deserializer
.try_skip(PeekableTokenKind::Comma, SyntaxError::ExpectedComma)
}
}

impl<'de> deer::ArrayAccess<'de> for ArrayAccess<'_, '_, 'de> {
fn is_dirty(&self) -> bool {
self.dirty
}

fn context(&self) -> &Context {
self.deserializer.context()
}

fn next<T>(&mut self) -> Option<Result<T, ArrayAccessError>>
where
T: Deserialize<'de>,
{
let mut errors = ErrorAccumulator::new();

if self.dirty {
// we parse in a way where every subsequent invocation (except the first one)
// needs to parse the `,` that is the token, if that token is not present we will error
// out, but(!) will still attempt deserialization, as we can tolerate that error.

// the statement after this _will_ fail and return the visitor, therefore we don't
// need to check for EOF
if let Err(error) = self.try_skip_comma() {
errors.extend_one(error);
}
}

self.dirty = true;

let peek_key = self.deserializer.peek();

// we check for `is_none` here because we could be EOF, in that case we're "done", we will
// error out at `.end()`
if peek_key.is_none() || peek_key == Some(PeekableTokenKind::ArrayEnd) {
return None;
}

self.expected += 1;

let value = T::deserialize(&mut *self.deserializer);

Some(value.change_context(ArrayAccessError))
}

fn size_hint(&self) -> Option<usize> {
None
}

fn end(self) -> Result<(), ArrayAccessError> {
self.deserializer.stack.pop();

let result = match self.deserializer.peek() {
None => Err(Report::new(SyntaxError::UnexpectedEof.into_error())
.attach(Position::new(self.deserializer.offset()))),
Some(PeekableTokenKind::ArrayEnd) => Ok(()),
Some(_) => Err(ArrayLengthError::new(&self, self.expected)),
};

skip_tokens(&mut self.deserializer.tokenizer, &Token::Array);

result.change_context(ArrayAccessError)
}
}
Loading

0 comments on commit 3ed367d

Please sign in to comment.