Skip to content

Commit

Permalink
Make more things work
Browse files Browse the repository at this point in the history
  • Loading branch information
davidpdrsn committed Oct 16, 2022
1 parent d8d28cb commit 78b415b
Show file tree
Hide file tree
Showing 2 changed files with 202 additions and 55 deletions.
183 changes: 141 additions & 42 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ use std::{any::Any, collections::HashMap, fmt};
use serde::{Deserialize, Serialize};
use speedy::{Readable, Writable};

// TODO(david):
// - tuple structs
// - vec
// - map
// - enums, including option and result
// - modifying
// - derive

#[cfg(test)]
mod tests;

Expand All @@ -17,13 +25,13 @@ pub trait Reflect: Any + Send + 'static {

fn patch(&mut self, value: &dyn Reflect);

fn as_struct(&self) -> Option<&dyn Struct> {
None
}
fn to_value(&self) -> Value;

fn as_struct_mut(&mut self) -> Option<&mut dyn Struct> {
None
}
fn clone_reflect(&self) -> Box<dyn Reflect>;

fn as_struct(&self) -> Option<&dyn Struct>;

fn as_struct_mut(&mut self) -> Option<&mut dyn Struct>;
}

impl dyn Reflect {
Expand All @@ -42,6 +50,44 @@ impl dyn Reflect {
}
}

impl Reflect for Box<dyn Reflect> {
fn as_any(&self) -> &dyn Any {
<dyn Reflect as Reflect>::as_any(&**self)
}

fn as_any_mut(&mut self) -> &mut dyn Any {
<dyn Reflect as Reflect>::as_any_mut(&mut **self)
}

fn as_reflect(&self) -> &dyn Reflect {
<dyn Reflect as Reflect>::as_reflect(&**self)
}

fn as_reflect_mut(&mut self) -> &mut dyn Reflect {
<dyn Reflect as Reflect>::as_reflect_mut(&mut **self)
}

fn patch(&mut self, value: &dyn Reflect) {
<dyn Reflect as Reflect>::patch(&mut **self, value)
}

fn to_value(&self) -> Value {
<dyn Reflect as Reflect>::to_value(&**self)
}

fn clone_reflect(&self) -> Box<dyn Reflect> {
<dyn Reflect as Reflect>::clone_reflect(&**self)
}

fn as_struct(&self) -> Option<&dyn Struct> {
<dyn Reflect as Reflect>::as_struct(&**self)
}

fn as_struct_mut(&mut self) -> Option<&mut dyn Struct> {
<dyn Reflect as Reflect>::as_struct_mut(&mut **self)
}
}

macro_rules! impl_for_core_types {
($($ty:ident)*) => {
$(
Expand All @@ -64,24 +110,32 @@ macro_rules! impl_for_core_types {

fn patch(&mut self, value: &dyn Reflect) {
if let Some(value) = value.as_any().downcast_ref::<Self>() {
*self = value.to_owned();
*self = value.clone();
}
}
}

impl FromReflect for $ty {
fn from_reflect(reflect: &dyn Reflect) -> Option<Self> {
Some(reflect.downcast_ref::<$ty>()?.to_owned())
fn clone_reflect(&self) -> Box<dyn Reflect> {
Box::new(self.clone())
}
}

impl IntoValue for $ty {
fn into_value(self) -> Value {
Value(ValueInner::$ty(self))
fn to_value(&self) -> Value {
Value::from(self.to_owned())
}

fn as_struct(&self) -> Option<&dyn Struct> {
None
}

fn as_struct_mut(&mut self) -> Option<&mut dyn Struct> {
None
}
}

impl private::Sealed for $ty {}
impl FromReflect for $ty {
fn from_reflect(reflect: &dyn Reflect) -> Option<Self> {
Some(reflect.downcast_ref::<$ty>()?.clone())
}
}
)*
};
}
Expand All @@ -102,8 +156,6 @@ pub trait Struct: Reflect {

fn field_mut(&mut self, name: &str) -> Option<&mut dyn Reflect>;

fn into_value(self) -> StructValue;

fn fields(&self) -> FieldsIter<'_>;

fn fields_mut(&mut self) -> FieldsIterMut<'_>;
Expand Down Expand Up @@ -193,6 +245,14 @@ impl Reflect for StructValue {
}
}

fn clone_reflect(&self) -> Box<dyn Reflect> {
Box::new(self.clone())
}

fn to_value(&self) -> Value {
Value(ValueInner::StructValue(self.clone()))
}

fn as_struct(&self) -> Option<&dyn Struct> {
Some(self)
}
Expand All @@ -211,10 +271,6 @@ impl Struct for StructValue {
Some(self.fields.get_mut(name)?)
}

fn into_value(self) -> StructValue {
self
}

fn fields(&self) -> FieldsIter<'_> {
let iter = self
.fields
Expand All @@ -232,14 +288,26 @@ impl Struct for StructValue {
}
}

impl FromReflect for StructValue {
fn from_reflect(reflect: &dyn Reflect) -> Option<Self> {
let struct_ = reflect.as_struct()?;
let this = struct_
.fields()
.fold(StructValue::builder(), |builder, (name, value)| {
builder.set(name, value.to_value())
});
Some(this.build())
}
}

#[derive(Default)]
pub struct StructValueBuilder {
fields: HashMap<String, Value>,
}

impl StructValueBuilder {
pub fn set(mut self, name: impl Into<String>, value: impl IntoValue) -> Self {
self.fields.insert(name.into(), value.into_value());
pub fn set(mut self, name: impl Into<String>, value: impl Into<Value>) -> Self {
self.fields.insert(name.into(), value.into());
self
}

Expand Down Expand Up @@ -270,10 +338,25 @@ impl Reflect for Value {
self.0.as_reflect_mut()
}

#[allow(warnings)]
fn patch(&mut self, value: &dyn Reflect) {
self.0.patch(value)
}

fn clone_reflect(&self) -> Box<dyn Reflect> {
Box::new(self.clone())
}

fn to_value(&self) -> Value {
self.clone()
}

fn as_struct(&self) -> Option<&dyn Struct> {
self.0.as_struct()
}

fn as_struct_mut(&mut self) -> Option<&mut dyn Struct> {
self.0.as_struct_mut()
}
}

impl fmt::Debug for Value {
Expand Down Expand Up @@ -324,13 +407,45 @@ macro_rules! value_inner {
$(
Self::$ident(inner) => {
if let Some(value) = value.downcast_ref::<$ident>() {
*inner = value.to_owned();
*inner = value.clone();
}
},
)*
}
}

fn to_value(&self) -> Value {
Value(self.clone())
}

fn clone_reflect(&self) -> Box<dyn Reflect> {
Box::new(self.clone())
}

fn as_struct(&self) -> Option<&dyn Struct> {
if let ValueInner::StructValue(value) = self {
Some(value)
} else {
None
}
}

fn as_struct_mut(&mut self) -> Option<&mut dyn Struct> {
if let ValueInner::StructValue(value) = self {
Some(value)
} else {
None
}
}
}

$(
impl From<$ident> for Value {
fn from(value: $ident) -> Self {
Self(ValueInner::$ident(value))
}
}
)*
};
}

Expand All @@ -357,19 +472,3 @@ value_inner! {
StructValue,
}
}

mod private {
pub trait Sealed {}
}

pub trait IntoValue: private::Sealed {
fn into_value(self) -> Value;
}

impl IntoValue for StructValue {
fn into_value(self) -> Value {
Value(ValueInner::StructValue(self))
}
}

impl private::Sealed for StructValue {}
74 changes: 61 additions & 13 deletions src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::any::Any;

use crate::{FieldsIter, FieldsIterMut, FromReflect, Reflect, Struct, StructValue};
use crate::{FieldsIter, FieldsIterMut, FromReflect, Reflect, Struct, StructValue, Value};

#[derive(Default)]
#[derive(Default, Clone, Eq, PartialEq, Debug)]
struct Foo {
field: i32,
}
Expand Down Expand Up @@ -32,6 +32,17 @@ impl Reflect for Foo {
}
}

fn clone_reflect(&self) -> Box<dyn Reflect> {
Box::new(self.clone())
}

fn to_value(&self) -> Value {
StructValue::builder()
.set("field", self.field)
.build()
.to_value()
}

fn as_struct(&self) -> Option<&dyn Struct> {
Some(self)
}
Expand Down Expand Up @@ -67,10 +78,6 @@ impl Struct for Foo {
None
}

fn into_value(self) -> StructValue {
StructValue::builder().set("field", self.field).build()
}

fn fields(&self) -> FieldsIter<'_> {
let iter = std::iter::once(("field", self.field.as_reflect()));
FieldsIter::new(iter)
Expand Down Expand Up @@ -119,11 +126,6 @@ fn patching_struct_value() {
);
}

// #[test]
// fn patching_value() {
// todo!()
// }

#[test]
fn from_reflect() {
let foo = Foo::default();
Expand All @@ -137,11 +139,11 @@ fn from_reflect() {
#[test]
fn serialize_deserialize() {
let foo = Foo::default();
let struct_value = foo.into_value();
let struct_value = foo.to_value();

let json = serde_json::to_string(&struct_value).unwrap();

let struct_value = serde_json::from_str::<StructValue>(&json).unwrap();
let struct_value = serde_json::from_str::<Value>(&json).unwrap();
let foo = Foo::from_reflect(&struct_value).unwrap();

assert_eq!(foo.field, 0);
Expand All @@ -159,3 +161,49 @@ fn fields() {
}
}
}

#[test]
fn struct_value_from_reflect() {
let value = StructValue::builder().set("foo", 42).build();
let reflect = value.as_reflect();

let value = StructValue::from_reflect(reflect).unwrap();

assert_eq!(
value.field("foo").unwrap().downcast_ref::<i32>().unwrap(),
&42,
);
}

#[test]
fn box_dyn_reflect_as_reflect() {
let foo = Foo::default();
let mut box_dyn_reflect = Box::new(foo) as Box<dyn Reflect>;

assert_eq!(
box_dyn_reflect
.as_struct()
.unwrap()
.field("field")
.unwrap()
.downcast_ref::<i32>()
.unwrap(),
&0,
);

box_dyn_reflect.patch(&StructValue::builder().set("field", 42).build());

assert_eq!(
box_dyn_reflect
.as_struct()
.unwrap()
.field("field")
.unwrap()
.downcast_ref::<i32>()
.unwrap(),
&42,
);

let foo = Foo::from_reflect(&box_dyn_reflect).unwrap();
assert_eq!(foo, Foo { field: 42 });
}

0 comments on commit 78b415b

Please sign in to comment.