#![doc = include_str!("../README.md")]
mod derive;
mod fields;
mod generic_helpers;
mod lists_and_arguments;
mod model;
use std::error::Error;
use either_n::Either2;
use proc_macro2::{Ident, Span, TokenStream};
use syn::{Attribute, ConstParam, Expr, FnArg, GenericParam, Path, Stmt, Type, TypeParam};
pub use proc_macro2;
pub use quote::{format_ident, quote, ToTokens};
pub use syn;
pub use derive::*;
pub use fields::*;
pub use lists_and_arguments::*;
pub use model::Item;
pub(crate) fn generic_parameters_have_same_name(
generic_parameter1: &GenericParam,
generic_parameter2: &GenericParam,
) -> bool {
match (generic_parameter1, generic_parameter2) {
(GenericParam::Type(gtp1), GenericParam::Type(gtp2)) => gtp1.ident == gtp2.ident,
(GenericParam::Lifetime(glp1), GenericParam::Lifetime(glp2)) => {
glp1.lifetime.ident == glp2.lifetime.ident
}
(GenericParam::Const(gcp1), GenericParam::Const(gcp2)) => gcp1.ident == gcp2.ident,
_ => false,
}
}
pub(crate) fn generic_param_to_generic_argument_token_stream(
trait_generic_parameter: &GenericParam,
) -> TokenStream {
match trait_generic_parameter {
GenericParam::Const(ConstParam { ident, .. })
| GenericParam::Type(TypeParam { ident, .. }) => ident.to_token_stream(),
GenericParam::Lifetime(lifetime) => lifetime.to_token_stream(),
}
}
pub fn dyn_error_to_compile_error_tokens(err: Box<dyn Error>) -> TokenStream {
let error_as_string = syn::LitStr::new(&err.to_string(), Span::call_site());
quote!(compile_error!(#error_as_string);)
}
pub struct Trait {
pub name: Path,
pub generic_parameters: Option<Vec<GenericParam>>,
pub items: Vec<TraitItem>,
}
type HandlerResult = Result<Vec<Stmt>, Box<dyn Error>>;
pub enum TraitItem {
Method {
name: Ident,
generic_parameters: Option<Vec<GenericParam>>,
self_type: TypeOfSelf,
other_parameters: Vec<FnArg>,
return_type: Option<Type>,
handler: Box<dyn for<'a> Fn(Item<'a>) -> HandlerResult>,
},
AssociatedFunction {
name: Ident,
generic_parameters: Option<Vec<GenericParam>>,
parameters: Vec<FnArg>,
return_type: Option<Type>,
handler: Box<dyn for<'a> Fn(&'a mut Structure) -> HandlerResult>,
},
}
#[derive(Clone, Copy)]
pub enum TypeOfSelf {
Reference,
MutableReference,
Owned,
}
impl TypeOfSelf {
fn as_parameter_tokens(&self) -> TokenStream {
match self {
TypeOfSelf::Reference => quote!(&self),
TypeOfSelf::MutableReference => quote!(&mut self),
TypeOfSelf::Owned => quote!(self),
}
}
fn as_matcher_tokens(&self) -> TokenStream {
match self {
TypeOfSelf::Reference => quote!(ref),
TypeOfSelf::MutableReference => quote!(ref mut),
TypeOfSelf::Owned => TokenStream::default(),
}
}
}
impl TraitItem {
pub fn new_method(
name: Ident,
generic_parameters: Option<Vec<GenericParam>>,
self_type: TypeOfSelf,
other_parameters: Vec<FnArg>,
return_type: Option<Type>,
handler: impl for<'a> Fn(Item<'a>) -> HandlerResult + 'static,
) -> Self {
Self::Method {
name,
generic_parameters,
self_type,
other_parameters,
return_type,
handler: Box::new(handler),
}
}
pub fn new_associated_function(
name: Ident,
generic_parameters: Option<Vec<GenericParam>>,
parameters: Vec<FnArg>,
return_type: Option<Type>,
handler: impl for<'a> Fn(&'a mut Structure) -> HandlerResult + 'static,
) -> Self {
Self::AssociatedFunction {
name,
generic_parameters,
parameters,
return_type,
handler: Box::new(handler),
}
}
}
pub struct EnumStructure {
name: Ident,
attrs: Vec<Attribute>,
variants: Vec<EnumVariant>,
}
impl EnumStructure {
pub fn get_variants(&self) -> &[EnumVariant] {
&self.variants
}
pub fn get_variants_mut(&mut self) -> &mut [EnumVariant] {
self.variants.as_mut_slice()
}
}
impl HasAttributes for EnumStructure {
fn get_attributes(&self) -> &[Attribute] {
&self.attrs
}
}
pub struct EnumVariant {
full_path: Path,
pub idx: usize,
fields: Fields,
}
pub struct StructStructure {
name: Ident,
fields: Fields,
}
pub trait Constructable {
fn get_constructor_path(&self) -> Path;
fn build_constructor(
&self,
generator: impl Fn(NamedOrUnnamedField) -> Result<Expr, Box<dyn Error>>,
) -> Result<Expr, Box<dyn std::error::Error>>;
fn get_fields(&self) -> &Fields;
fn get_fields_mut(&mut self) -> &mut Fields;
}
impl Constructable for StructStructure {
fn build_constructor(
&self,
generator: impl Fn(NamedOrUnnamedField) -> Result<Expr, Box<dyn Error>>,
) -> Result<Expr, Box<dyn std::error::Error>> {
self.fields
.to_constructor(generator, self.name.clone().into())
}
fn get_fields(&self) -> &Fields {
&self.fields
}
fn get_fields_mut(&mut self) -> &mut Fields {
&mut self.fields
}
fn get_constructor_path(&self) -> Path {
self.name.clone().into()
}
}
impl Constructable for EnumVariant {
fn build_constructor(
&self,
generator: impl Fn(NamedOrUnnamedField) -> Result<Expr, Box<dyn Error>>,
) -> Result<Expr, Box<dyn std::error::Error>> {
self.fields
.to_constructor(generator, self.full_path.clone())
}
fn get_fields(&self) -> &Fields {
&self.fields
}
fn get_fields_mut(&mut self) -> &mut Fields {
&mut self.fields
}
fn get_constructor_path(&self) -> Path {
self.full_path.clone()
}
}
pub trait HasAttributes {
fn get_attributes(&self) -> &[Attribute];
}
pub enum Structure {
Struct(StructStructure),
Enum(EnumStructure),
}
pub enum ConstructableStructure<'a> {
Struct(&'a mut StructStructure),
EnumVariant(&'a mut EnumVariant, &'a [Attribute]),
}
impl Structure {
fn all_fields(&self) -> impl Iterator<Item = NamedOrUnnamedField<'_>> {
match self {
Structure::Struct(r#struct) => Either2::One(r#struct.get_fields().fields_iterator()),
Structure::Enum(r#enum) => Either2::Two(
r#enum
.variants
.iter()
.flat_map(|variant| variant.get_fields().fields_iterator()),
),
}
}
pub fn get_attributes(&self) -> &[Attribute] {
match self {
Structure::Struct(r#struct) => r#struct.fields.get_field_attributes(),
Structure::Enum(r#enum) => r#enum.attrs.as_slice(),
}
}
pub fn get_name(&self) -> &Ident {
match self {
Structure::Struct(r#struct) => &r#struct.name,
Structure::Enum(r#enum) => &r#enum.name,
}
}
}
impl Constructable for ConstructableStructure<'_> {
fn build_constructor(
&self,
generator: impl Fn(NamedOrUnnamedField) -> Result<Expr, Box<dyn Error>>,
) -> Result<Expr, Box<dyn std::error::Error>> {
match self {
ConstructableStructure::Struct(r#struct) => r#struct.build_constructor(generator),
ConstructableStructure::EnumVariant(enum_variant, _) => {
enum_variant.build_constructor(generator)
}
}
}
fn get_fields(&self) -> &Fields {
match self {
ConstructableStructure::Struct(r#struct) => r#struct.get_fields(),
ConstructableStructure::EnumVariant(enum_variant, _) => enum_variant.get_fields(),
}
}
fn get_fields_mut(&mut self) -> &mut Fields {
match self {
ConstructableStructure::Struct(r#struct) => r#struct.get_fields_mut(),
ConstructableStructure::EnumVariant(enum_variant, _) => enum_variant.get_fields_mut(),
}
}
fn get_constructor_path(&self) -> Path {
match self {
ConstructableStructure::Struct(r#struct) => r#struct.get_constructor_path(),
ConstructableStructure::EnumVariant(enum_variant, _) => {
enum_variant.get_constructor_path()
}
}
}
}
impl<'a> ConstructableStructure<'a> {
pub fn as_enum_variant(&'a self) -> Option<&'a EnumVariant> {
if let Self::EnumVariant(variant, _) = self {
Some(&**variant)
} else {
None
}
}
pub fn all_attributes<'b: 'a>(&'b self) -> impl Iterator<Item = &'b Attribute> + '_ {
match self {
ConstructableStructure::Struct(r#struct) => {
Either2::One(r#struct.get_fields().get_field_attributes().iter())
}
ConstructableStructure::EnumVariant(r#enum, parent_attrs) => Either2::Two(
parent_attrs
.iter()
.chain(r#enum.get_fields().get_field_attributes().iter()),
),
}
}
}
pub fn path_to_string(path: Path) -> String {
let mut buf = String::new();
if path.leading_colon.is_some() {
buf.push_str("::");
}
for (idx, segment) in path.segments.iter().enumerate() {
buf.push_str(&segment.ident.to_string());
if !segment.arguments.is_empty() {
todo!()
}
if idx != path.segments.len() - 1 {
buf.push_str("::");
}
}
buf
}