Skip to content
Closed
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
18 changes: 9 additions & 9 deletions specta-macros/src/type/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use attr::*;
use proc_macro2::TokenStream;
use quote::{format_ident, quote, ToTokens};
use r#enum::parse_enum;
use proc_macro2::TokenStream;
use quote::{ToTokens, format_ident, quote};
use r#struct::parse_struct;
use syn::{parse, Data, DeriveInput, GenericParam};
use syn::{Data, DeriveInput, GenericParam, parse};

use crate::utils::{parse_attrs, unraw_raw_ident, AttributeValue};
use crate::utils::{AttributeValue, parse_attrs, unraw_raw_ident};

use self::generics::{
add_type_to_where_clause, generics_with_ident_and_bounds_only, generics_with_ident_only,
Expand Down Expand Up @@ -76,7 +76,7 @@ pub fn derive(input: proc_macro::TokenStream) -> syn::Result<proc_macro::TokenSt
return Err(syn::Error::new(
attrs.key.span(),
"specta: invalid formatted attribute",
))
));
}
}
}
Expand Down Expand Up @@ -194,10 +194,10 @@ pub fn derive(input: proc_macro::TokenStream) -> syn::Result<proc_macro::TokenSt
}
}

#[automatically_derived]
impl #bounds #crate_ref::NamedType for #ident #type_args #where_bound {
const ID: #crate_ref::SpectaID = SID;
}
// #[automatically_derived]
// impl #bounds #crate_ref::NamedType for #ident #type_args #where_bound {
// const ID: #crate_ref::SpectaID = SID;
// }

#flatten_impl

Expand Down
4 changes: 2 additions & 2 deletions specta-serde/src/validate.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::collections::HashSet;

use specta::{
SpectaID, TypeCollection,
datatype::{DataType, Enum, EnumRepr, Fields, Generic, Literal, Primitive},
internal::{skip_fields, skip_fields_named},
SpectaID, TypeCollection,
};

use crate::Error;
Expand Down Expand Up @@ -172,7 +172,7 @@ fn is_valid_map_key(
DataType::Generic(g) => {
let ty = generics
.iter()
.find(|(gen, _)| gen == g)
.find(|(ge, _)| ge == g)
.map(|(_, dt)| dt)
.expect("bruh");

Expand Down
20 changes: 19 additions & 1 deletion specta-typescript/examples/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,25 @@ pub struct B {
}

fn main() {
let mut types = TypeCollection::default().register::<B>();
let types = TypeCollection::default().register::<B>();

// Using `NamedType`
let ndt = types.get(A::SID).unwrap();

// Naive alternative
let ndt = types
.get(match A::definition(types) {
specta::datatype::DataType::Reference(r) => r.sid(),
_ => panic!(),
})
.unwrap();

// We could add this to remove one of the panics as it's an invariant of the Type trait?
let ndt = match A::definition(types) {
specta::datatype::DataType::Reference(r) => r.get(types),
_ => panic!(),
};

// .register::<Testing>()
// .register::<serde_yaml::Value>();
// println!("{:#?}", types.get(Testing::ID).unwrap());
Expand Down
4 changes: 2 additions & 2 deletions specta-typescript/src/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ fn inner(
DataType::Generic(g) => {
let mut ty = generics
.iter()
.find(|(gen, _)| gen == g)
.find(|(ge, _)| ge == g)
.map(|(_, dt)| dt)
.unwrap()
.clone(); // TODO: Properly handle this error
Expand Down Expand Up @@ -205,7 +205,7 @@ fn resolve_generics(dt: &mut DataType, generics: &[(Generic, DataType)]) {
// TODO: Functions main documentation should explain this.
*dt = generics
.iter()
.find(|(gen, _)| gen == g)
.find(|(ge, _)| ge == g)
.map(|(_, dt)| dt.clone())
.unwrap_or(DataType::Generic(g.clone()));
}
Expand Down
16 changes: 10 additions & 6 deletions specta-typescript/src/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,18 @@ use std::{
};

use specta::{
SpectaID, TypeCollection,
datatype::{
DataType, Enum, EnumRepr, Field, Fields, List, Literal, Map, NamedDataType, Primitive,
Reference, Tuple,
},
NamedType, SpectaID, TypeCollection,
};

use crate::{
legacy::js_doc_builder, reserved_names::*, Any, BigIntExportBehavior, Error, Format,
Typescript, Unknown,
Any, BigIntExportBehavior, Error, Format, Typescript, Unknown,
legacy::js_doc_builder,
reserved_names::*,
types::{ANY_ID, NEVER_ID, UNKNOWN_ID},
};

/// Generate an `export Type = ...` Typescript string for a specific [`DataType`].
Expand Down Expand Up @@ -205,7 +207,7 @@ fn primitive_dt(
BigIntExportBehavior::Fail => {
return Err(Error::BigIntForbidden {
path: location.join("."),
})
});
}
},
Primitive::bool => "boolean",
Expand Down Expand Up @@ -879,10 +881,12 @@ fn reference_dt(
) -> Result<(), Error> {
// TODO: Legacy stuff
{
if r.sid() == Any::<()>::ID {
if r.sid() == ANY_ID {
s.push_str("any");
} else if r.sid() == Unknown::<()>::ID {
} else if r.sid() == UNKNOWN_ID {
s.push_str("unknown");
} else if r.sid() == NEVER_ID {
s.push_str("never");
} else {
let ndt = types.get(r.sid()).unwrap(); // TODO: Error handling

Expand Down
47 changes: 19 additions & 28 deletions specta-typescript/src/types.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::fmt::Debug;

use specta::{
Type, TypeCollection,
datatype::{DataType, Reference},
NamedType, Type, TypeCollection,
};

/// Cast a Rust type to a Typescript `any` type.
Expand Down Expand Up @@ -39,19 +39,16 @@ use specta::{
/// ```
pub struct Any<T = ()>(T);

pub(crate) const ANY_ID: specta::SpectaID = specta::internal::construct::sid(
"Any",
concat!("::", module_path!(), ":", line!(), ":", column!()),
);
impl<T> Type for Any<T> {
fn definition(types: &mut TypeCollection) -> DataType {
DataType::Reference(Reference::construct(Self::ID, [], false))
fn definition(_: &mut TypeCollection) -> DataType {
DataType::Reference(Reference::construct(ANY_ID, [], false))
}
}

impl<T> NamedType for Any<T> {
const ID: specta::SpectaID = specta::internal::construct::sid(
"Any",
concat!("::", module_path!(), ":", line!(), ":", column!()),
);
}

impl<T: Debug> Debug for Any<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Any").field(&self.0).finish()
Expand Down Expand Up @@ -113,19 +110,16 @@ impl<T: serde::Serialize> serde::Serialize for Any<T> {
/// ```
pub struct Unknown<T = ()>(T);

pub(crate) const UNKNOWN_ID: specta::SpectaID = specta::internal::construct::sid(
"Unknown",
concat!("::", module_path!(), ":", line!(), ":", column!()),
);
impl<T> Type for Unknown<T> {
fn definition(types: &mut TypeCollection) -> DataType {
DataType::Reference(Reference::construct(Self::ID, [], false))
fn definition(_: &mut TypeCollection) -> DataType {
DataType::Reference(Reference::construct(UNKNOWN_ID, [], false))
}
}

impl<T> NamedType for Unknown<T> {
const ID: specta::SpectaID = specta::internal::construct::sid(
"Unknown",
concat!("::", module_path!(), ":", line!(), ":", column!()),
);
}

impl<T: Debug> Debug for Unknown<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Any").field(&self.0).finish()
Expand Down Expand Up @@ -187,19 +181,16 @@ impl<T: serde::Serialize> serde::Serialize for Unknown<T> {
/// ```
pub struct Never<T = ()>(T);

pub(crate) const NEVER_ID: specta::SpectaID = specta::internal::construct::sid(
"Any",
concat!("::", module_path!(), ":", line!(), ":", column!()),
);
impl<T> Type for Never<T> {
fn definition(types: &mut TypeCollection) -> DataType {
DataType::Reference(Reference::construct(Self::ID, [], false))
fn definition(_: &mut TypeCollection) -> DataType {
DataType::Reference(Reference::construct(NEVER_ID, [], false))
}
}

impl<T> NamedType for Never<T> {
const ID: specta::SpectaID = specta::internal::construct::sid(
"Unknown",
concat!("::", module_path!(), ":", line!(), ":", column!()),
);
}

impl<T: Debug> Debug for Never<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Any").field(&self.0).finish()
Expand Down
2 changes: 1 addition & 1 deletion specta-util/src/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// - Remove dependency on `serde_json`
// - Don't ignore doctests

use crate::{datatype::Literal, DataType, Type, TypeCollection};
use specta::{DataType, Type, TypeCollection, datatype::Literal};

#[doc(hidden)]
pub use serde_json;
Expand Down
11 changes: 10 additions & 1 deletion specta/src/datatype/reference.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Helpers for generating [Type::reference] implementations.

use crate::SpectaID;
use crate::{SpectaID, TypeCollection, datatype::NamedDataType};

use super::{DataType, Generic};

Expand All @@ -15,6 +15,7 @@ pub struct Reference {

impl Reference {
/// TODO: Explain invariant.
/// TODO: Can this force that the type is in the typemap at the point of the `Reference` being created to ensure `Self::get` never panics.
pub fn construct(
sid: SpectaID,
generics: impl Into<Vec<(Generic, DataType)>>,
Expand Down Expand Up @@ -46,6 +47,14 @@ impl Reference {
pub fn inline(&self) -> bool {
self.inline
}

#[doc(hidden)] // TODO: Stablise
pub fn get<'a>(&self, types: &'a TypeCollection) -> &'a NamedDataType {
// TODO: Different panic for missing vs placeholder
types
.get(self.sid)
.expect("a type with a reference must be registered to the TypeMap")
}
}

impl From<Reference> for DataType {
Expand Down
16 changes: 6 additions & 10 deletions specta/src/export.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
use std::{
collections::HashMap,
sync::{Mutex, OnceLock, PoisonError},
};
use std::sync::{Mutex, OnceLock, PoisonError};

use crate::{NamedType, SpectaID, TypeCollection};
use crate::{Type, TypeCollection};

// Global type store for collecting custom types to export.
static TYPES: OnceLock<Mutex<HashMap<SpectaID, fn(&mut TypeCollection)>>> = OnceLock::new();
static TYPES: OnceLock<Mutex<Vec<fn(&mut TypeCollection)>>> = OnceLock::new();

/// Get the global type store containing all automatically registered types.
///
Expand All @@ -15,14 +12,13 @@ static TYPES: OnceLock<Mutex<HashMap<SpectaID, fn(&mut TypeCollection)>>> = Once
/// Note that when enabling the `export` feature, you will not be able to enable the `unsafe_code` lint as [`ctor`](https://docs.rs/ctor) (which is used internally) is marked unsafe.
///
pub fn export() -> TypeCollection {
// TODO: Make `TYPES` should just hold a `TypeCollection` directly???
let types = TYPES
.get_or_init(Default::default)
.lock()
.unwrap_or_else(PoisonError::into_inner);

let mut map = TypeCollection::default();
for (_, export) in types.iter() {
for export in types.iter() {
export(&mut map);
}
map
Expand All @@ -36,13 +32,13 @@ pub mod internal {

// Called within ctor functions to register a type.
#[doc(hidden)]
pub fn register<T: NamedType>() {
pub fn register<T: Type>() {
let mut types = TYPES
.get_or_init(Default::default)
.lock()
.unwrap_or_else(PoisonError::into_inner);

types.insert(T::ID, |types| {
types.push(|types| {
// The side-effect of this is registering the type.
T::definition(types);
});
Expand Down
2 changes: 1 addition & 1 deletion specta/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ mod r#type;
mod type_collection;

// TODO: Can we just move the trait here or `#[doc(inline)]`
pub use r#type::{Flatten, NamedType, Type};
pub use r#type::{Flatten, Type};
// #[doc(inline)]
pub use specta_id::SpectaID;
pub use type_collection::TypeCollection;
Expand Down
18 changes: 4 additions & 14 deletions specta/src/type.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,21 @@
use crate::{datatype::DataType, SpectaID, TypeCollection};
use crate::{TypeCollection, datatype::DataType};

mod impls;
mod macros;
// TODO: We don't care much about these cause they are gonna go so this will do for now.
#[cfg(feature = "derive")]
mod legacy_impls;

/// Provides runtime type information that can be fed into a language exporter to generate a type definition in another language.
/// Provides runtime type information that can be fed into a language exporter to generate a type definition for another language.
/// Avoid implementing this trait yourself where possible and use the [`Type`](derive@crate::Type) macro instead.
///
/// This should be only implemented via the [`Type`](derive@crate::Type) macro.
/// This should be implemented by the [`Type`](derive@crate::Type) macro.
/// TODO: Discuss how to avoid custom implementations.
pub trait Type {
/// returns a [`DataType`](crate::datatype::DataType) that represents the type.
/// This will also register any dependent types into the [`TypeCollection`].
/// This will also register this and any dependent types into the [`TypeCollection`].
fn definition(types: &mut TypeCollection) -> DataType;
}

/// represents a type that can be converted into [`NamedDataType`](crate::NamedDataType).
/// This will be implemented for all types with the [Type] derive macro.
///
/// TODO: Discuss which types this should be implemented for.
///
/// This should be only implemented via the [`Type`](derive@crate::Type) macro.
pub trait NamedType: Type {
const ID: SpectaID;
}

/// A marker trait for compile-time validation of which types can be flattened.
pub trait Flatten: Type {}
4 changes: 0 additions & 4 deletions specta/src/type/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,6 @@ macro_rules! _impl_containers {
}
}

impl<T: NamedType> NamedType for $container<T> {
const ID: SpectaID = T::ID;
}

impl<T: Flatten> Flatten for $container<T> {}
)+}
}
Expand Down
Loading
Loading