Skip to content
This repository was archived by the owner on Apr 15, 2022. It is now read-only.

Improve type name handling #15

Merged
merged 1 commit into from
May 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions src/describe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ use crate::{PrimitiveValue, TypeName};

// A *data structure* that can be described by schematic.
pub trait Describe: Sized {
// The unique name identifying the type.
fn type_name() -> TypeName;

fn describe<D>(describer: D) -> Result<D::Ok, D::Error>
where
D: Describer;
Expand Down
21 changes: 21 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@ pub struct TypeName {
/// Note that this may not be the same module that the type is publicly exported
/// from in the owning crate.
pub module: Cow<'static, str>,

/// Any generic parameters, if the type is generic.
///
/// For non-generic types, this list will be empty. For generic types, this list
/// should reflect the names of each of the generic parameters in order of
/// declaration.
pub type_params: Vec<TypeName>,
}

impl TypeName {
Expand All @@ -93,6 +100,20 @@ impl TypeName {
Self {
name: name.into(),
module: module.into(),
type_params: Vec::new(),
}
}

pub fn generic<N, M, P>(name: N, module: M, type_params: P) -> Self
where
N: Into<Cow<'static, str>>,
M: Into<Cow<'static, str>>,
P: Into<Vec<TypeName>>,
{
Self {
name: name.into(),
module: module.into(),
type_params: type_params.into(),
}
}
}
84 changes: 76 additions & 8 deletions src/primitive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,15 @@ use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedL
/// }
/// ```
macro_rules! impl_describe {
( $( $ty:ident $( < $( $generic:ident ),* > )? => $describe:ident, )* ) => {
( $( $ty:ident => $describe:ident, )* ) => {
$(
impl $( < $( $generic ),* > )? Describe for $ty $( < $( $generic ),* > where $( $generic: Describe ),* )? {
impl Describe for $ty {
fn type_name() -> TypeName {
$crate::TypeName::new(stringify!($ty), "")
}

fn describe<D: Describer>(describer: D) -> Result<D::Ok, D::Error> {
describer.$describe $( ::<$( $generic, )* >)?()
describer.$describe()
}
}
)*
Expand All @@ -49,15 +53,35 @@ impl_describe! {

bool => describe_bool,
char => describe_char,
Option<T> => describe_option,
}

impl<T: Describe> Describe for Option<T> {
fn type_name() -> TypeName {
TypeName::generic("Option", "core::option", vec![T::type_name()])
}

fn describe<D>(describer: D) -> Result<D::Ok, D::Error>
where
D: Describer,
{
describer.describe_option::<T>()
}
}

macro_rules! describe_seq {
( $( $ty:ident => $module:literal, )* ) => {
$(
impl<T> Describe for $ty<T> where T: Describe {
fn type_name() -> TypeName {
$crate::TypeName::generic(
stringify!($ty),
$module,
vec![T::type_name()],
)
}

fn describe<D: Describer>(describer: D) -> Result<D::Ok, D::Error> {
describer.describe_seq::<T>(TypeName::new(stringify!($ty), $module), None)
describer.describe_seq::<T>(Self::type_name(), None)
}
}
)*
Expand All @@ -74,24 +98,44 @@ describe_seq! {
}

impl<K: Describe, V: Describe> Describe for HashMap<K, V> {
fn type_name() -> TypeName {
TypeName::generic(
"HashMap",
"std::collections::hash_map",
vec![K::type_name(), V::type_name()],
)
}

fn describe<D>(describer: D) -> Result<D::Ok, D::Error>
where
D: Describer,
{
describer.describe_map::<K, V>(TypeName::new("HashMap", "std::collections::hash_map"))
describer.describe_map::<K, V>(Self::type_name())
}
}

impl<K: Describe, V: Describe> Describe for BTreeMap<K, V> {
fn type_name() -> TypeName {
TypeName::generic(
"BTreeMap",
"alloc::collections::btree_map",
vec![K::type_name(), V::type_name()],
)
}

fn describe<D>(describer: D) -> Result<D::Ok, D::Error>
where
D: Describer,
{
describer.describe_map::<K, V>(TypeName::new("BTreeMap", "alloc::collections::btree_map"))
describer.describe_map::<K, V>(Self::type_name())
}
}

impl<'a> Describe for &'a str {
fn type_name() -> TypeName {
TypeName::new("str", "")
}

fn describe<D>(describer: D) -> Result<D::Ok, D::Error>
where
D: Describer,
Expand All @@ -101,15 +145,23 @@ impl<'a> Describe for &'a str {
}

impl Describe for String {
fn type_name() -> TypeName {
TypeName::new("String", "alloc::string")
}

fn describe<D>(describer: D) -> Result<D::Ok, D::Error>
where
D: Describer,
{
describer.describe_string(TypeName::new("String", "alloc::string"))
describer.describe_string(Self::type_name())
}
}

impl Describe for () {
fn type_name() -> TypeName {
TypeName::new("()", "")
}

fn describe<D: Describer>(describer: D) -> Result<D::Ok, D::Error> {
describer.describe_unit()
}
Expand All @@ -122,6 +174,14 @@ impl Describe for () {
macro_rules! describe_tuple {
( $($ty:ident),* ) => {
impl<$( $ty, )*> Describe for ($( $ty, )*) where $( $ty: Describe, )* {
fn type_name() -> $crate::TypeName {
TypeName::generic(
"()",
"",
vec![$( $ty::type_name(), )*],
)
}

fn describe<Desc: Describer>(describer: Desc) -> Result<Desc::Ok, Desc::Error> {
let mut describer = describer.describe_tuple()?;
$(
Expand Down Expand Up @@ -154,6 +214,10 @@ impl<'a, T> Describe for &'a [T]
where
T: Describe,
{
fn type_name() -> TypeName {
TypeName::generic("[]", "", vec![T::type_name()])
}

fn describe<D>(describer: D) -> Result<D::Ok, D::Error>
where
D: Describer,
Expand All @@ -172,6 +236,10 @@ macro_rules! describe_array {
( $( $len:expr ),* ) => {
$(
impl<T> Describe for [T; $len] where T: Describe {
fn type_name() -> TypeName {
TypeName::generic(stringify!([;$len]), "", vec![T::type_name()])
}

fn describe<D: Describer>(describer: D) -> Result<D::Ok, D::Error> {
describer.describe_array::<T>($len)
}
Expand Down
11 changes: 2 additions & 9 deletions src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,7 @@ impl Schema {
/// use schematic::{Schema, Struct, TypeName};
///
/// let schema = Schema::Struct(Struct {
/// name: TypeName {
/// name: "MyStruct".into(),
/// module: "my_crate::my_module".into(),
/// },
/// name: TypeName::new("MyStruct", "my_crate::my_module"),
/// fields: vec![],
/// });
///
Expand Down Expand Up @@ -491,10 +488,6 @@ impl fmt::Display for PrimitiveValue {
#[macro_export]
macro_rules! type_name {
($ty:ty) => {
$crate::TypeName {
// TODO: Support stripping off
name: std::borrow::Cow::Borrowed(stringify!($ty)),
module: std::borrow::Cow::Borrowed(module_path!()),
}
$crate::TypeName::new(stringify!($ty), module_path!())
};
}
4 changes: 2 additions & 2 deletions tests/collections.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use pretty_assertions::assert_eq;
use schematic::{Array, Schema, Sequence, TypeName};
use schematic::{Array, Describe, Schema, Sequence, TypeName};

#[test]
fn describe_vec() {
let expected = Schema::Seq(Box::new(Sequence {
name: TypeName::new("Vec", "alloc::vec"),
name: TypeName::generic("Vec", "alloc::vec", vec![<u32 as Describe>::type_name()]),
element: Schema::U32,
len: None,
}));
Expand Down
12 changes: 10 additions & 2 deletions tests/describe_enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@ enum Simple {
}

impl Describe for Simple {
fn type_name() -> TypeName {
schematic::type_name!(Simple)
}

fn describe<D: Describer>(describer: D) -> std::result::Result<D::Ok, D::Error> {
let mut describer = describer.describe_enum(schematic::type_name!(Simple))?;
let mut describer = describer.describe_enum(Self::type_name())?;
describer.describe_unit_variant("Foo", None)?;
describer.describe_unit_variant("Bar", None)?;
describer.end()
Expand Down Expand Up @@ -46,8 +50,12 @@ enum WithData {
}

impl Describe for WithData {
fn type_name() -> TypeName {
schematic::type_name!(WithData)
}

fn describe<D: Describer>(describer: D) -> std::result::Result<D::Ok, D::Error> {
let mut describer = describer.describe_enum(schematic::type_name!(WithData))?;
let mut describer = describer.describe_enum(Self::type_name())?;

describer.describe_unit_variant("Foo", None)?;

Expand Down
19 changes: 15 additions & 4 deletions tests/describe_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ pub struct ManualStruct {
}

impl Describe for ManualStruct {
fn type_name() -> TypeName {
schematic::type_name!(ManualStruct)
}

fn describe<D: Describer>(describer: D) -> Result<D::Ok, D::Error> {
let mut describer = describer.describe_struct(schematic::type_name!(ManualStruct))?;
let mut describer = describer.describe_struct(Self::type_name())?;
describer.describe_field::<bool>("field")?;
describer.describe_field::<u32>("another")?;
describer.end()
Expand All @@ -33,9 +37,12 @@ fn describe_struct() {
pub struct ManualTupleStruct(bool, u32);

impl Describe for ManualTupleStruct {
fn type_name() -> TypeName {
schematic::type_name!(ManualTupleStruct)
}

fn describe<D: Describer>(describer: D) -> Result<D::Ok, D::Error> {
let mut describer =
describer.describe_tuple_struct(schematic::type_name!(ManualTupleStruct))?;
let mut describer = describer.describe_tuple_struct(Self::type_name())?;
describer.describe_element::<bool>()?;
describer.describe_element::<u32>()?;
describer.end()
Expand Down Expand Up @@ -68,8 +75,12 @@ pub struct NestedStruct {
}

impl Describe for NestedStruct {
fn type_name() -> TypeName {
schematic::type_name!(NestedStruct)
}

fn describe<D: Describer>(describer: D) -> Result<D::Ok, D::Error> {
let mut describer = describer.describe_struct(schematic::type_name!(NestedStruct))?;
let mut describer = describer.describe_struct(Self::type_name())?;
describer.describe_field::<ManualStruct>("manual_struct")?;
describer.describe_field::<ManualTupleStruct>("tuple_struct")?;
describer.end()
Expand Down