Skip to content

Commit

Permalink
TypeMap + TypeCollection (#294)
Browse files Browse the repository at this point in the history
* wip

* fix size_hint

* call `language.format` on `TypeMap::export_to`

* rename `TypeMap` to `TypeCollection`

* move `specta_util::export` to `specta::export`

---------

Co-authored-by: Oscar Beaumont <[email protected]>
  • Loading branch information
oscartbeaumont and Oscar Beaumont authored Dec 4, 2024
1 parent a0950d0 commit d13f097
Show file tree
Hide file tree
Showing 41 changed files with 398 additions and 347 deletions.
3 changes: 1 addition & 2 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ edition = "2021"
publish = false

[dependencies]
specta = { path = "../specta", features = ["derive"] }
specta = { path = "../specta", features = ["derive", "export"] }
specta-typescript = { path = "../specta-typescript" }
specta-util = { path = "../specta-util", features = ["export"] }

[lints]
workspace = true
6 changes: 3 additions & 3 deletions examples/examples/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ pub struct TypeTwo {

fn main() {
// Export as string
let string = specta_util::export().export(Typescript::default()).unwrap();
let string = specta::export().export(Typescript::default()).unwrap();
println!("{string}");

// Export to file
specta_util::export()
specta::export()
.export_to(Typescript::default(), "./bindings.ts")
.unwrap();

// Override the export configuration.
specta_util::export()
specta::export()
.export_to(
Typescript::default()
// Be aware this won't be typesafe unless your using a ser/deserializer that converts BigInt types to a number.
Expand Down
7 changes: 5 additions & 2 deletions specta-go/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
html_favicon_url = "https://github.com/oscartbeaumont/specta/raw/main/.github/logo-128.png"
)]

use specta::{datatype::DataType, Generics, Type, TypeMap};
use specta::{datatype::DataType, Generics, Type, TypeCollection};

/// TODO
pub fn export<T: Type>() -> Result<String, String> {
datatype(&T::inline(&mut TypeMap::default(), Generics::Definition))
datatype(&T::inline(
&mut TypeCollection::default(),
Generics::Definition,
))
}

fn datatype(t: &DataType) -> Result<String, String> {
Expand Down
4 changes: 2 additions & 2 deletions specta-jsdoc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

use std::{borrow::Cow, path::Path};

use specta::{Language, TypeMap};
use specta::{Language, TypeCollection};
use specta_typescript::{BigIntExportBehavior, CommentFormatterFn, FormatterFn};

// TODO: Ensure this is up to our `Typescript` exporters standards.
Expand Down Expand Up @@ -79,7 +79,7 @@ impl Language for JSDoc {
type Error = specta_typescript::ExportError; // TODO: Custom error type

// TODO: Make this properly export JSDoc
fn export(&self, type_map: TypeMap) -> Result<String, Self::Error> {
fn export(&self, _type_map: &TypeCollection) -> Result<String, Self::Error> {
todo!("Coming soon...");
// let mut out = self.0.header.to_string();
// if !self.0.remove_default_header {
Expand Down
7 changes: 5 additions & 2 deletions specta-kotlin/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@

use specta::{
datatype::{DataType, PrimitiveType},
Generics, Type, TypeMap,
Generics, Type, TypeCollection,
};

/// TODO
pub fn export<T: Type>() -> Result<String, String> {
datatype(&T::inline(&mut TypeMap::default(), Generics::Definition))
datatype(&T::inline(
&mut TypeCollection::default(),
Generics::Definition,
))
}

fn datatype(t: &DataType) -> Result<String, String> {
Expand Down
2 changes: 1 addition & 1 deletion specta-macros/src/specta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ pub fn attribute(item: proc_macro::TokenStream) -> syn::Result<proc_macro::Token
macro_rules! #wrapper {
// We take in `$function` from the invocation so we have `fn_name::<concrete_generics_types>`
(@export_fn; $function:path) => {{
fn export(type_map: &mut #crate_ref::TypeMap) -> #crate_ref::datatype::Function {
fn export(type_map: &mut #crate_ref::TypeCollection) -> #crate_ref::datatype::Function {
#crate_ref::internal::get_fn_datatype(
$function as fn(#(#arg_signatures),*) -> _,
#function_asyncness,
Expand Down
13 changes: 6 additions & 7 deletions specta-macros/src/type/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ pub fn derive(input: proc_macro::TokenStream) -> syn::Result<proc_macro::TokenSt
.unwrap_or_else(|| ident.to_token_stream());

let crate_ref: TokenStream = container_attrs.crate_name.clone().unwrap_or(quote!(specta));
let internal_crate_ref: TokenStream = quote!(specta_util); // TODO: This should be overridable by attribute but it's not. // TODO: container_attrs.crate_name.clone().unwrap_or(

let name = container_attrs.rename.clone().unwrap_or_else(|| {
unraw_raw_ident(&format_ident!("{}", raw_ident.to_string())).to_token_stream()
Expand Down Expand Up @@ -119,9 +118,9 @@ pub fn derive(input: proc_macro::TokenStream) -> syn::Result<proc_macro::TokenSt

quote! {
#[allow(non_snake_case)]
#[#internal_crate_ref::export::internal::ctor]
#[#crate_ref::export::internal::ctor]
fn #export_fn_name() {
#internal_crate_ref::export::internal::register::<#ident<#(#generic_params),*>>();
#crate_ref::export::internal::register::<#ident<#(#generic_params),*>>();
}
}
});
Expand All @@ -138,7 +137,7 @@ pub fn derive(input: proc_macro::TokenStream) -> syn::Result<proc_macro::TokenSt

#[automatically_derived]
#type_impl_heading {
fn inline(type_map: &mut #crate_ref::TypeMap, generics: #crate_ref::Generics) -> #crate_ref::datatype::DataType {
fn inline(type_map: &mut #crate_ref::TypeCollection, generics: #crate_ref::Generics) -> #crate_ref::datatype::DataType {
let generics = match generics {
#crate_ref::Generics::Definition => DEFINITION_GENERICS,
#crate_ref::Generics::Provided(generics) => generics,
Expand All @@ -147,7 +146,7 @@ pub fn derive(input: proc_macro::TokenStream) -> syn::Result<proc_macro::TokenSt
#inlines
}

fn reference(type_map: &mut #crate_ref::TypeMap, generics: &[#crate_ref::datatype::DataType]) -> #crate_ref::datatype::reference::Reference {
fn reference(type_map: &mut #crate_ref::TypeCollection, generics: &[#crate_ref::datatype::DataType]) -> #crate_ref::datatype::reference::Reference {
#reference
}
}
Expand All @@ -158,7 +157,7 @@ pub fn derive(input: proc_macro::TokenStream) -> syn::Result<proc_macro::TokenSt
#sid
}

fn named_data_type(type_map: &mut #crate_ref::TypeMap, generics: &[#crate_ref::datatype::DataType]) -> #crate_ref::datatype::NamedDataType {
fn named_data_type(type_map: &mut #crate_ref::TypeCollection, generics: &[#crate_ref::datatype::DataType]) -> #crate_ref::datatype::NamedDataType {
#crate_ref::internal::construct::named_data_type(
#name.into(),
#comments.into(),
Expand All @@ -169,7 +168,7 @@ pub fn derive(input: proc_macro::TokenStream) -> syn::Result<proc_macro::TokenSt
)
}

fn definition_named_data_type(type_map: &mut #crate_ref::TypeMap) -> #crate_ref::datatype::NamedDataType {
fn definition_named_data_type(type_map: &mut #crate_ref::TypeCollection) -> #crate_ref::datatype::NamedDataType {
#crate_ref::internal::construct::named_data_type(
#name.into(),
#comments.into(),
Expand Down
7 changes: 5 additions & 2 deletions specta-rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
html_favicon_url = "https://github.com/oscartbeaumont/specta/raw/main/.github/logo-128.png"
)]

use specta::{datatype::DataType, Generics, Type, TypeMap};
use specta::{datatype::DataType, Generics, Type, TypeCollection};

/// TODO
pub fn export<T: Type>() -> Result<String, String> {
datatype(&T::inline(&mut TypeMap::default(), Generics::Definition))
datatype(&T::inline(
&mut TypeCollection::default(),
Generics::Definition,
))
}

fn datatype(t: &DataType) -> Result<String, String> {
Expand Down
14 changes: 7 additions & 7 deletions specta-serde/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use specta::{
DataType, EnumRepr, EnumType, EnumVariants, LiteralType, PrimitiveType, StructFields,
},
internal::{resolve_generics, skip_fields, skip_fields_named},
SpectaID, TypeMap,
SpectaID, TypeCollection,
};

// TODO: The error should show a path to the type causing the issue like the BigInt error reporting.
Expand All @@ -32,13 +32,13 @@ pub enum SerdeError {
/// Check that a [DataType] is a valid for Serde.
///
/// This can be used by exporters which wanna do export-time checks that all types are compatible with Serde formats.
pub fn is_valid_ty(dt: &DataType, type_map: &TypeMap) -> Result<(), SerdeError> {
pub fn is_valid_ty(dt: &DataType, type_map: &TypeCollection) -> Result<(), SerdeError> {
is_valid_ty_internal(dt, type_map, &mut Default::default())
}

fn is_valid_ty_internal(
dt: &DataType,
type_map: &TypeMap,
type_map: &TypeCollection,
checked_references: &mut HashSet<SpectaID>,
) -> Result<(), SerdeError> {
match dt {
Expand Down Expand Up @@ -106,7 +106,7 @@ fn is_valid_ty_internal(
}

// Typescript: Must be assignable to `string | number | symbol` says Typescript.
fn is_valid_map_key(key_ty: &DataType, type_map: &TypeMap) -> Result<(), SerdeError> {
fn is_valid_map_key(key_ty: &DataType, type_map: &TypeCollection) -> Result<(), SerdeError> {
match key_ty {
DataType::Any => Ok(()),
DataType::Primitive(ty) => match ty {
Expand Down Expand Up @@ -171,7 +171,7 @@ fn is_valid_map_key(key_ty: &DataType, type_map: &TypeMap) -> Result<(), SerdeEr
}

// Serde does not allow serializing a variant of certain types of enum's.
fn validate_enum(e: &EnumType, type_map: &TypeMap) -> Result<(), SerdeError> {
fn validate_enum(e: &EnumType, type_map: &TypeCollection) -> Result<(), SerdeError> {
// You can't `#[serde(skip)]` your way to an empty enum.
let valid_variants = e.variants().iter().filter(|(_, v)| !v.skip()).count();
if valid_variants == 0 && !e.variants().is_empty() {
Expand All @@ -187,7 +187,7 @@ fn validate_enum(e: &EnumType, type_map: &TypeMap) -> Result<(), SerdeError> {
}

// Checks for specially internally tagged enums.
fn validate_internally_tag_enum(e: &EnumType, type_map: &TypeMap) -> Result<(), SerdeError> {
fn validate_internally_tag_enum(e: &EnumType, type_map: &TypeCollection) -> Result<(), SerdeError> {
for (_variant_name, variant) in e.variants() {
match &variant.inner() {
EnumVariants::Unit => {}
Expand Down Expand Up @@ -215,7 +215,7 @@ fn validate_internally_tag_enum(e: &EnumType, type_map: &TypeMap) -> Result<(),
// Which makes sense when you can't represent `{ "type": "A" } & string` in a single JSON value.
fn validate_internally_tag_enum_datatype(
ty: &DataType,
type_map: &TypeMap,
type_map: &TypeCollection,
) -> Result<(), SerdeError> {
match ty {
// `serde_json::Any` can be *technically* be either valid or invalid based on the actual data but we are being strict and reject it.
Expand Down
7 changes: 5 additions & 2 deletions specta-swift/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@

use specta::{
datatype::{DataType, PrimitiveType},
Generics, Type, TypeMap,
Generics, Type, TypeCollection,
};

/// TODO
pub fn export<T: Type>() -> Result<String, String> {
datatype(&T::inline(&mut TypeMap::default(), Generics::Definition))
datatype(&T::inline(
&mut TypeCollection::default(),
Generics::Definition,
))
}

fn datatype(t: &DataType) -> Result<String, String> {
Expand Down
10 changes: 7 additions & 3 deletions specta-typescript/src/js_doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ use std::borrow::Borrow;

use specta::{
datatype::{DeprecatedType, GenericType},
TypeMap,
TypeCollection,
};
use typescript::CommentFormatterArgs;

use super::*;

pub fn typedef_named_datatype(cfg: &Typescript, typ: &NamedDataType, type_map: &TypeMap) -> Output {
pub fn typedef_named_datatype(
cfg: &Typescript,
typ: &NamedDataType,
type_map: &TypeCollection,
) -> Output {
typedef_named_datatype_inner(
&ExportContext {
cfg,
Expand All @@ -24,7 +28,7 @@ pub fn typedef_named_datatype(cfg: &Typescript, typ: &NamedDataType, type_map: &
fn typedef_named_datatype_inner(
ctx: &ExportContext,
typ: &NamedDataType,
type_map: &TypeMap,
type_map: &TypeCollection,
) -> Output {
let name = typ.name();
let docs = typ.docs();
Expand Down
Loading

0 comments on commit d13f097

Please sign in to comment.