use proc_macro::TokenStream;
use quote::quote;
use syn::{parse, Data, DataStruct, DeriveInput, Field, Fields, FieldsUnnamed, Ident};
#[proc_macro_derive(New)]
pub fn derive_new(input: TokenStream) -> TokenStream {
for_new_type(&parse(input).unwrap(), "New", |name, field| {
let ty = &field.ty;
quote! {
impl #name {
pub fn new(value: #ty) -> Self {
Self(value)
}
}
}
.into()
})
}
#[proc_macro_derive(Inner)]
pub fn derive_inner(input: TokenStream) -> TokenStream {
for_new_type(&parse(input).unwrap(), "Inner", |name, field| {
let ty = &field.ty;
quote! {
impl #name {
pub fn inner(&self) -> &#ty {
&self.0
}
}
}
.into()
})
}
#[proc_macro_derive(From)]
pub fn derive_from(input: TokenStream) -> TokenStream {
for_new_type(&parse(input).unwrap(), "From", |name, field| {
let ty = &field.ty;
quote! {
impl std::convert::From<#ty> for #name {
fn from(value: #ty) -> Self {
Self(value)
}
}
}
.into()
})
}
#[proc_macro_derive(Add)]
pub fn derive_add(input: TokenStream) -> TokenStream {
for_new_type(&parse(input).unwrap(), "Add", |name, _| {
quote! {
impl std::ops::Add for #name {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0 + rhs.0)
}
}
}
.into()
})
}
#[proc_macro_derive(AddAssign)]
pub fn derive_add_assign(input: TokenStream) -> TokenStream {
for_new_type(&parse(input).unwrap(), "AddAssign", |name, _| {
quote! {
impl std::ops::AddAssign for #name {
fn add_assign(&mut self, rhs: Self) {
self.0 += rhs.0;
}
}
}
.into()
})
}
#[proc_macro_derive(Sub)]
pub fn derive_sub(input: TokenStream) -> TokenStream {
for_new_type(&parse(input).unwrap(), "Sub", |name, _| {
quote! {
impl std::ops::Sub for #name {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self(self.0 - rhs.0)
}
}
}
.into()
})
}
#[proc_macro_derive(SubAssign)]
pub fn derive_sub_assign(input: TokenStream) -> TokenStream {
for_new_type(&parse(input).unwrap(), "SubAssign", |name, _| {
quote! {
impl std::ops::SubAssign for #name {
fn sub_assign(&mut self, rhs: Self) {
self.0 -= rhs.0;
}
}
}
.into()
})
}
#[proc_macro_derive(Mul)]
pub fn derive_mul(input: TokenStream) -> TokenStream {
for_new_type(&parse(input).unwrap(), "Mul", |name, _| {
quote! {
impl std::ops::Mul for #name {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Self(self.0 * rhs.0)
}
}
}
.into()
})
}
#[proc_macro_derive(MulAssign)]
pub fn derive_mul_assign(input: TokenStream) -> TokenStream {
for_new_type(&parse(input).unwrap(), "MulAssign", |name, _| {
quote! {
impl std::ops::MulAssign for #name {
fn mul_assign(&mut self, rhs: Self) {
self.0 *= rhs.0;
}
}
}
.into()
})
}
#[proc_macro_derive(MulScalar)]
pub fn derive_mul_scalar(input: TokenStream) -> TokenStream {
for_new_type(&parse(input).unwrap(), "Mul", |name, field| {
let ty = &field.ty;
quote! {
impl std::ops::Mul<#ty> for #name {
type Output = Self;
fn mul(self, rhs: #ty) -> Self::Output {
Self(self.0 * rhs)
}
}
}
.into()
})
}
#[proc_macro_derive(MulAssignScalar)]
pub fn derive_mul_assign_scalar(input: TokenStream) -> TokenStream {
for_new_type(&parse(input).unwrap(), "MulAssign", |name, field| {
let ty = &field.ty;
quote! {
impl std::ops::MulAssign<#ty> for #name {
fn mul_assign(&mut self, rhs: #ty) {
self.0 *= rhs;
}
}
}
.into()
})
}
#[proc_macro_derive(Div)]
pub fn derive_div(input: TokenStream) -> TokenStream {
for_new_type(&parse(input).unwrap(), "Div", |name, _| {
quote! {
impl std::ops::Div for #name {
type Output = Self;
fn div(self, rhs: Self) -> Self::Output {
Self(self.0 / rhs.0)
}
}
}
.into()
})
}
#[proc_macro_derive(DivAssign)]
pub fn derive_div_assign(input: TokenStream) -> TokenStream {
for_new_type(&parse(input).unwrap(), "DivAssign", |name, _| {
quote! {
impl std::ops::DivAssign for #name {
fn div_assign(&mut self, rhs: Self) {
self.0 /= rhs.0;
}
}
}
.into()
})
}
#[proc_macro_derive(DivScalar)]
pub fn derive_div_scalar(input: TokenStream) -> TokenStream {
for_new_type(&parse(input).unwrap(), "Div", |name, field| {
let ty = &field.ty;
quote! {
impl std::ops::Div<#ty> for #name {
type Output = Self;
fn div(self, rhs: #ty) -> Self::Output {
Self(self.0 / rhs)
}
}
}
.into()
})
}
#[proc_macro_derive(DivAssignScalar)]
pub fn derive_div_assign_scalar(input: TokenStream) -> TokenStream {
for_new_type(&parse(input).unwrap(), "DivAssign", |name, field| {
let ty = &field.ty;
quote! {
impl std::ops::DivAssign<#ty> for #name {
fn div_assign(&mut self, rhs: #ty) {
self.0 /= rhs;
}
}
}
.into()
})
}
#[proc_macro_derive(Rem)]
pub fn derive_rem(input: TokenStream) -> TokenStream {
for_new_type(&parse(input).unwrap(), "Rem", |name, _| {
quote! {
impl std::ops::Rem for #name {
type Output = Self;
fn rem(self, rhs: Self) -> Self::Output {
Self(self.0 % rhs.0)
}
}
}
.into()
})
}
#[proc_macro_derive(RemAssign)]
pub fn derive_rem_assign(input: TokenStream) -> TokenStream {
for_new_type(&parse(input).unwrap(), "RemAssign", |name, _| {
quote! {
impl std::ops::RemAssign for #name {
fn rem_assign(&mut self, rhs: Self) {
self.0 %= rhs.0;
}
}
}
.into()
})
}
#[proc_macro_derive(RemScalar)]
pub fn derive_rem_scalar(input: TokenStream) -> TokenStream {
for_new_type(&parse(input).unwrap(), "Rem", |name, field| {
let ty = &field.ty;
quote! {
impl std::ops::Rem<#ty> for #name {
type Output = Self;
fn rem(self, rhs: #ty) -> Self::Output {
Self(self.0 % rhs)
}
}
}
.into()
})
}
#[proc_macro_derive(RemAssignScalar)]
pub fn derive_rem_assign_scalar(input: TokenStream) -> TokenStream {
for_new_type(&parse(input).unwrap(), "RemAssign", |name, field| {
let ty = &field.ty;
quote! {
impl std::ops::RemAssign<#ty> for #name {
fn rem_assign(&mut self, rhs: #ty) {
self.0 %= rhs;
}
}
}
.into()
})
}
fn for_new_type<F>(ast: &DeriveInput, t: &str, f: F) -> TokenStream
where
F: Fn(&Ident, &Field) -> TokenStream,
{
match &ast.data {
Data::Struct(DataStruct {
struct_token: _,
fields:
Fields::Unnamed(FieldsUnnamed {
paren_token: _,
unnamed,
}),
semi_token: _,
}) if unnamed.len() == 1 => {
let field = unnamed.first().unwrap();
f(&ast.ident, field)
}
_ => panic!("#[derive({t})] is only defined for newtypes (unary tuple structs)"),
}
}