Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

deer implement Deserialize for built-in types (Part 2) #1875

Closed
wants to merge 29 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
ea15fff
feat: &[u8]
indietyp Jan 18, 2023
80f4425
fix: import
indietyp Jan 18, 2023
cff877e
feat: implement `OnceCell`
indietyp Jan 25, 2023
f78bb79
feat: implement all cells
indietyp Jan 25, 2023
a946c34
feat: tuples start
indietyp Jan 25, 2023
163c020
feat: implement tuples
indietyp Jan 25, 2023
c30064c
feat: `PhantomData`
indietyp Jan 25, 2023
bac7dd7
feat: rename `phantom` to `mem`
indietyp Jan 25, 2023
b910982
feat: `ManuallyDrop`
indietyp Jan 25, 2023
e751478
feat: `Saturating`, `Wrapping`
indietyp Jan 25, 2023
77e3814
chore: merge `num` + `non_zero`
indietyp Jan 25, 2023
ef6d2e9
feat: `Reverse`
indietyp Jan 25, 2023
7a85f8e
feat: `Exclusive`
indietyp Jan 25, 2023
8c0d22b
feat: `Duration`
indietyp Jan 25, 2023
f15d6c9
Merge remote-tracking branch 'origin/main' into bm/deer/stdlib-core
indietyp Feb 14, 2023
e1cb40f
feat: start implementation on `Option<T>`
indietyp Feb 14, 2023
5a189c4
docs: explain
indietyp Feb 14, 2023
a9cbf9e
docs: chore
indietyp Feb 14, 2023
0224b86
Merge branch 'main' into bm/deer/stdlib-core
indietyp Mar 3, 2023
dbd411e
feat: implementation Option
indietyp Mar 3, 2023
bf300b5
fix: sized
indietyp Mar 3, 2023
9c57021
feat: Result
indietyp Mar 3, 2023
e3f36b1
Merge branch 'main' into bm/deer/stdlib-core
indietyp Mar 22, 2023
03d9254
Merge branch 'bm/deer/stdlib-core' of github.com:hashintel/hash into …
indietyp Mar 22, 2023
77f35b0
feat: implement result
indietyp Mar 22, 2023
c3f7864
feat: start ops
indietyp Mar 22, 2023
8c1a08b
feat: factor out common discriminator logic
indietyp Mar 22, 2023
77f680d
feat: Bound<T>
indietyp Mar 22, 2023
937f8d5
chore: imports
indietyp Mar 22, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions libs/deer/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@
//!
//! [`Location`]: core::panic::Location

// TODO: error cause (the error underlying the processed `Error` in the strain)

use alloc::{boxed::Box, format, string::String};
#[cfg(nightly)]
use core::any::Demand;
Expand Down
82 changes: 82 additions & 0 deletions libs/deer/src/ext.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use error_stack::{Context, Report};

pub(crate) trait TupleExt {
type Context: Context;
type Ok;

fn fold_reports(self) -> Result<Self::Ok, Report<Self::Context>>;
}

#[rustfmt::skip]
macro_rules! all_the_tuples {
($name:ident) => {
$name!([T1, T2], T3);
$name!([T1, T2, T3], T4);
$name!([T1, T2, T3, T4], T5);
$name!([T1, T2, T3, T4, T5], T6);
$name!([T1, T2, T3, T4, T5, T6], T7);
$name!([T1, T2, T3, T4, T5, T6, T7], T8);
$name!([T1, T2, T3, T4, T5, T6, T7, T8], T9);
$name!([T1, T2, T3, T4, T5, T6, T7, T8, T9], T10);
$name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], T11);
$name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], T12);
$name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], T13);
$name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], T14);
$name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], T15);
$name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], T16);
};
}

impl<T1, C: Context> TupleExt for (Result<T1, Report<C>>,) {
type Context = C;
type Ok = (T1,);

fn fold_reports(self) -> Result<Self::Ok, Report<Self::Context>> {
self.0.map(|value| (value,))
}
}

impl<T1, T2, C: Context> TupleExt for (Result<T1, Report<C>>, Result<T2, Report<C>>) {
type Context = C;
type Ok = (T1, T2);

fn fold_reports(self) -> Result<Self::Ok, Report<Self::Context>> {
match self {
(Ok(t1), Ok(t2)) => Ok((t1, t2)),
(Ok(_), Err(err)) | (Err(err), Ok(_)) => Err(err),
(Err(mut err1), Err(err2)) => {
err1.extend_one(err2);

Err(err1)
}
}
}
}

macro_rules! impl_tuple_ext {
([$($elem:ident),*], $other:ident) => {
#[allow(non_snake_case)]
impl<C: Context $(, $elem)*, $other> TupleExt for ($(Result<$elem, Report<C>>, )* Result<$other, Report<C>>) {
type Context = C;
type Ok = ($($elem ,)* $other);

fn fold_reports(self) -> Result<Self::Ok, Report<Self::Context>> {
let ( $($elem ,)* $other ) = self;

let lhs = ( $($elem ,)* ).fold_reports();

match (lhs, $other) {
(Ok(( $($elem ,)* )), Ok(rhs)) => Ok(($($elem ,)* rhs)),
(Ok(_), Err(err)) | (Err(err), Ok(_)) => Err(err),
(Err(mut lhs), Err(rhs)) => {
lhs.extend_one(rhs);

Err(lhs)
}
}
}
}
};
}

all_the_tuples!(impl_tuple_ext);
1 change: 1 addition & 0 deletions libs/deer/src/impls.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
mod core;
mod helpers;
12 changes: 11 additions & 1 deletion libs/deer/src/impls/core.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
mod array;
mod atomic;
mod bool;
mod bytes;
mod cell;
mod cmp;
mod floating;
mod integral;
mod non_zero;
mod mem;
mod num;
mod ops;
mod option;
mod result;
mod string;
mod sync;
mod time;
mod tuples;
mod unit;
39 changes: 39 additions & 0 deletions libs/deer/src/impls/core/bytes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use core::marker::PhantomData;

use error_stack::ResultExt;

use crate::{
error::{DeserializeError, VisitorError},
Deserialize, Deserializer, Document, Reflection, Schema, Visitor,
};

struct BytesVisitor<'de>(PhantomData<fn() -> &'de ()>);

impl<'de> Visitor<'de> for BytesVisitor<'de> {
type Value = &'de [u8];

fn expecting(&self) -> Document {
Self::Value::reflection()
}

fn visit_borrowed_bytes(self, v: &'de [u8]) -> error_stack::Result<Self::Value, VisitorError> {
Ok(v)
}
}

impl Reflection for [u8] {
fn schema(_: &mut Document) -> Schema {
// this type does not really exist in json-schema :/
// TODO: correct valid schema?
Schema::new("bytes")
}
}

impl<'de> Deserialize<'de> for &'de [u8] {
type Reflection = [u8];

fn deserialize<D: Deserializer<'de>>(de: D) -> error_stack::Result<Self, DeserializeError> {
de.deserialize_bytes(BytesVisitor(PhantomData))
.change_context(DeserializeError)
}
}
46 changes: 46 additions & 0 deletions libs/deer/src/impls/core/cell.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#[cfg(nightly)]
use core::cell::OnceCell;
use core::cell::{Cell, RefCell, SyncUnsafeCell, UnsafeCell};

use crate::{error::DeserializeError, Deserialize, Deserializer, Document, Reflection, Schema};

macro_rules! impl_cell {
($(#[$attr:meta])* $cell:ident) => {
$(#[$attr])*
impl<T> Reflection for $cell<T>
where
T: Reflection,
{
fn schema(doc: &mut Document) -> Schema {
T::schema(doc)
}
}

$(#[$attr])*
impl<'de, T> Deserialize<'de> for $cell<T>
where
T: Deserialize<'de>,
{
type Reflection = T::Reflection;

fn deserialize<D: Deserializer<'de>>(
de: D,
) -> error_stack::Result<Self, DeserializeError> {
T::deserialize(de).map(Self::from)
}
}
};

($($(#[$attr:meta])* $cell:ident),+ $(,)?) => {
$(impl_cell!($(#[$attr])* $cell);)*
};
}

impl_cell![
#[cfg(nightly)]
OnceCell,
SyncUnsafeCell,
Cell,
RefCell,
UnsafeCell
];
11 changes: 11 additions & 0 deletions libs/deer/src/impls/core/cmp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use core::cmp::Reverse;

use crate::{error::DeserializeError, Deserialize, Deserializer};

impl<'de, T: Deserialize<'de>> Deserialize<'de> for Reverse<T> {
type Reflection = T::Reflection;

fn deserialize<D: Deserializer<'de>>(de: D) -> error_stack::Result<Self, DeserializeError> {
T::deserialize(de).map(Reverse)
}
}
58 changes: 58 additions & 0 deletions libs/deer/src/impls/core/mem.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
use core::{marker::PhantomData, mem::ManuallyDrop};

use error_stack::{Result, ResultExt};

use crate::{
error::{DeserializeError, VisitorError},
Deserialize, Deserializer, Document, Reflection, Schema, Visitor,
};

struct PhantomDataVisitor<T: ?Sized>(PhantomData<T>);

impl<'de, T: ?Sized> Visitor<'de> for PhantomDataVisitor<T> {
type Value = PhantomData<T>;

fn expecting(&self) -> Document {
Self::Value::reflection()
}

fn visit_none(self) -> Result<Self::Value, VisitorError> {
Ok(PhantomData)
}

fn visit_null(self) -> Result<Self::Value, VisitorError> {
Ok(PhantomData)
}
}

pub struct PhantomDataReflection;

impl Reflection for PhantomDataReflection {
fn schema(_: &mut Document) -> Schema {
// TODO: this is also optional (none)
Schema::new("null")
}
}

impl<'de, T: ?Sized> Deserialize<'de> for PhantomData<T> {
type Reflection = PhantomDataReflection;

fn deserialize<D: Deserializer<'de>>(de: D) -> Result<Self, DeserializeError> {
de.deserialize_null(PhantomDataVisitor(PhantomData))
.change_context(DeserializeError)
}
}

impl<T: Reflection + ?Sized> Reflection for ManuallyDrop<T> {
fn schema(doc: &mut Document) -> Schema {
T::schema(doc)
}
}

impl<'de, T: Deserialize<'de>> Deserialize<'de> for ManuallyDrop<T> {
type Reflection = ManuallyDrop<T::Reflection>;

fn deserialize<D: Deserializer<'de>>(de: D) -> Result<Self, DeserializeError> {
T::deserialize(de).map(Self::new)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#[cfg(nightly)]
use core::num::Saturating;
use core::num::{
NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize,
NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping,
};

use error_stack::{Report, ResultExt};
Expand Down Expand Up @@ -69,3 +71,19 @@ impl_nonzero![
NonZeroI128 <- i128,
NonZeroIsize <- isize,
];

impl<'de, T: Deserialize<'de>> Deserialize<'de> for Wrapping<T> {
type Reflection = T::Reflection;

fn deserialize<D: Deserializer<'de>>(de: D) -> error_stack::Result<Self, DeserializeError> {
T::deserialize(de).map(Self)
}
}

impl<'de, T: Deserialize<'de>> Deserialize<'de> for Saturating<T> {
type Reflection = T::Reflection;

fn deserialize<D: Deserializer<'de>>(de: D) -> error_stack::Result<Self, DeserializeError> {
T::deserialize(de).map(Self)
}
}
Loading