Skip to content

Commit

Permalink
Add path to error
Browse files Browse the repository at this point in the history
  • Loading branch information
melody-rs committed May 31, 2024
1 parent 8165ec4 commit c1e7126
Show file tree
Hide file tree
Showing 11 changed files with 859 additions and 64 deletions.
21 changes: 17 additions & 4 deletions alox-48/examples/bad_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

fn main() {
let mut data = vec![
let data = [
0x04, 0x08, 0x5b, 0x06, 0x6f, 0x3a, 0x0c, 0x42, 0x61, 0x64, 0x44, 0x61, 0x74, 0x61, 0x08,
0x3a, 0x0a, 0x40, 0x67, 0x6f, 0x6f, 0x64, 0x5b, 0x06, 0x49, 0x22, 0x13, 0x68, 0x66, 0x6a,
0x76, 0x68, 0x6a, 0x76, 0x6a, 0x68, 0x76, 0x68, 0x6a, 0x76, 0x6c, 0x06, 0x3a, 0x06, 0x45,
Expand All @@ -17,9 +17,22 @@ fn main() {
0x6e, 0x67, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x67, 0x6f, 0x20, 0x77, 0x72, 0x6f, 0x6e, 0x67,
0x20, 0x68, 0x65, 0x72, 0x65, 0x20, 0x3a, 0x29, 0x06, 0x3b, 0x07, 0x54,
];
data[0x92] = 0x26;

let error = alox_48::from_bytes::<alox_48::Value>(data.as_slice()).expect_err("success??");
for i in 2..data.len() {
let mut data = data;
data[i] = b',';

println!("{error}");
let mut deserializer = alox_48::Deserializer::new(&data).unwrap();
let Err((error, trace)) =
alox_48::path_to_error::deserialize::<alox_48::Value>(&mut deserializer)
else {
continue;
};

println!("Error: {error}");
println!("Backtrace:");
for ctx in trace.context.iter().rev() {
println!(" {ctx}");
}
}
}
47 changes: 27 additions & 20 deletions alox-48/src/de/deserializer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@

use std::collections::BTreeSet;

use super::{ignored::Ignored, Error, Kind, Result};
use super::{ignored::Ignored, DeserializeSeed, Error, Kind, Result};
use crate::{tag::Tag, Deserialize, DeserializerTrait, Sym, Visitor};

/// The alox-48 deserializer.
#[derive(Debug, Clone)]
pub struct Deserializer<'de> {
cursor: Cursor<'de>,
pub(crate) cursor: Cursor<'de>,

objtable: Vec<usize>,
stack: Vec<usize>,
Expand All @@ -27,9 +27,9 @@ pub struct Deserializer<'de> {
}

#[derive(Debug, Clone)]
struct Cursor<'de> {
input: &'de [u8],
position: usize,
pub(crate) struct Cursor<'de> {
pub(crate) input: &'de [u8],
pub(crate) position: usize,
}

struct InstanceAccess<'de, 'a> {
Expand Down Expand Up @@ -152,6 +152,13 @@ impl<'de> Deserializer<'de> {
self.cursor.position
}

/// Returns the data that the deserializer is reading from.
///
/// This is useful for debugging.
pub fn data(&self) -> &'de [u8] {
self.cursor.input
}

fn read_packed_int(&mut self) -> Result<i32> {
// The bounds of a Ruby Marshal packed integer are [-(2**30), 2**30 - 1], anything beyond that
// gets serialized as a bignum.
Expand Down Expand Up @@ -577,11 +584,11 @@ impl<'de, 'a> super::InstanceAccess<'de> for &'a mut InstanceAccess<'de, 'a> {
))
}

fn value_deserialize<T>(self) -> Result<(T, Self::IvarAccess)>
fn value_deserialize_seed<V>(self, seed: V) -> Result<(V::Value, Self::IvarAccess)>
where
T: Deserialize<'de>,
V: DeserializeSeed<'de>,
{
let result = T::deserialize(&mut *self.deserializer)?;
let result = seed.deserialize(&mut *self.deserializer)?;

let len = self.deserializer.read_usize()?;
*self.len = len;
Expand All @@ -607,11 +614,11 @@ impl<'de, 'a> super::IvarAccess<'de> for IvarAccess<'de, 'a> {
self.deserializer.read_symbol_either().map(Some)
}

fn next_value<T>(&mut self) -> Result<T>
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
where
T: Deserialize<'de>,
V: DeserializeSeed<'de>,
{
T::deserialize(&mut *self.deserializer)
seed.deserialize(&mut *self.deserializer)
}

fn len(&self) -> usize {
Expand All @@ -624,16 +631,16 @@ impl<'de, 'a> super::IvarAccess<'de> for IvarAccess<'de, 'a> {
}

impl<'de, 'a> super::ArrayAccess<'de> for ArrayAccess<'de, 'a> {
fn next_element<T>(&mut self) -> Result<Option<T>>
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
where
T: Deserialize<'de>,
T: DeserializeSeed<'de>,
{
if *self.index >= self.len {
return Ok(None);
}
*self.index += 1;

T::deserialize(&mut *self.deserializer).map(Some)
seed.deserialize(&mut *self.deserializer).map(Some)
}

fn len(&self) -> usize {
Expand All @@ -646,23 +653,23 @@ impl<'de, 'a> super::ArrayAccess<'de> for ArrayAccess<'de, 'a> {
}

impl<'de, 'a> super::HashAccess<'de> for HashAccess<'de, 'a> {
fn next_key<K>(&mut self) -> Result<Option<K>>
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
where
K: Deserialize<'de>,
K: DeserializeSeed<'de>,
{
if *self.index >= self.len {
return Ok(None);
}
*self.index += 1;

K::deserialize(&mut *self.deserializer).map(Some)
seed.deserialize(&mut *self.deserializer).map(Some)
}

fn next_value<V>(&mut self) -> Result<V>
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
where
V: Deserialize<'de>,
V: DeserializeSeed<'de>,
{
V::deserialize(&mut *self.deserializer)
seed.deserialize(&mut *self.deserializer)
}

fn len(&self) -> usize {
Expand Down
14 changes: 11 additions & 3 deletions alox-48/src/de/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub enum Kind {
#[error("Unexpected negative length {0}")]
UnexpectedNegativeLength(i32),
/// Unrecognized tag was encountered.
#[error("Wrong tag {0}")]
#[error("Wrong tag 0x{0:X} ({})", unknown_tag_to_char(*_0))]
WrongTag(u8),
/// A symbol was invalid utf8.
/// All symbols in ruby should be valid.
Expand All @@ -47,16 +47,24 @@ pub enum Kind {
#[error("Expected a symbol got {0:?}")]
ExpectedSymbol(Tag),
/// End of input.
#[error("End of input.")]
#[error("End of input")]
Eof,
/// Version mismatch.
#[error("Version error, expected [4, 8], got {0:?}")]
VersionError([u8; 2]),
/// A custom error thrown by a visitor.
#[error("Custom error: {0}")]
#[error("{0}")]
Message(String),
}

fn unknown_tag_to_char(tag: u8) -> char {
if tag.is_ascii() && !(tag.is_ascii_control() || tag.is_ascii_whitespace()) {
tag as char
} else {
'.'
}
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Unexpected<'a> {
Nil,
Expand Down
18 changes: 16 additions & 2 deletions alox-48/src/de/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,25 @@ use std::{
};

use super::{
traits::VisitorOption, ArrayAccess, Deserialize, DeserializerTrait, Error, HashAccess, Result,
Unexpected, Visitor,
traits::VisitorOption, ArrayAccess, Deserialize, DeserializeSeed, DeserializerTrait, Error,
HashAccess, Result, Unexpected, Visitor,
};
use crate::Sym;

impl<'de, T> DeserializeSeed<'de> for PhantomData<T>
where
T: Deserialize<'de>,
{
type Value = T;

fn deserialize<D>(self, deserializer: D) -> Result<Self::Value>
where
D: DeserializerTrait<'de>,
{
T::deserialize(deserializer)
}
}

struct IntVisitor;

impl<'de> Visitor<'de> for IntVisitor {
Expand Down
4 changes: 2 additions & 2 deletions alox-48/src/de/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ pub use error::{Error, Kind, Unexpected};

pub use deserializer::Deserializer;
pub use traits::{
ArrayAccess, Deserialize, Deserializer as DeserializerTrait, HashAccess, InstanceAccess,
IvarAccess, Visitor, VisitorInstance, VisitorOption,
ArrayAccess, Deserialize, DeserializeSeed, Deserializer as DeserializerTrait, HashAccess,
InstanceAccess, IvarAccess, Visitor, VisitorInstance, VisitorOption,
};
Loading

0 comments on commit c1e7126

Please sign in to comment.