Skip to content

Commit

Permalink
Merge pull request #36 from kas-gui/work
Browse files Browse the repository at this point in the history
v0.10: rename singleton! → impl_anon!
  • Loading branch information
dhardy authored Sep 8, 2023
2 parents 73c70c2 + 73c5512 commit 3fe5057
Show file tree
Hide file tree
Showing 15 changed files with 153 additions and 56 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.10.0] — 2023-09-07

- Rename `singleton!``impl_anon!` (#36)
- Reorganise `impl-tools-lib`: new `anon` and `scope` public modules (#36)

## [0.9.1] — 2023-09-07

- Fix clone for fields which auto-deref (issue #34)
Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "impl-tools"
version = "0.9.1"
version = "0.10.0"
authors = ["Diggory Hardy <[email protected]>"]
edition = "2021"
license = "MIT/Apache-2.0"
Expand All @@ -22,7 +22,7 @@ default-features = false
version = "2.0.0"

[dependencies.impl-tools-lib]
version = "0.9.1"
version = "0.10.0"
path = "lib"

[dev-dependencies]
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,17 +159,17 @@ impl_tools::impl_scope! {
Caveat: `rustfmt` won't currently touch the contents. Hopefully that
[can be fixed](https://github.com/rust-lang/rustfmt/pull/5538)!

### Singleton
### Impl Anon

`singleton!` is a function-like macro to construct a single-use struct with
`impl_anon!` is a function-like macro to construct a single-use struct with
custom implementations (similar: [RFC#2604](https://github.com/rust-lang/rfcs/pull/2604)).

Example:
```rust
use std::fmt;
fn main() {
let world = "world";
let says_hello_world = impl_tools::singleton! {
let says_hello_world = impl_tools::impl_anon! {
struct(&'static str = world);
impl fmt::Display for Self {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Expand Down
2 changes: 1 addition & 1 deletion lib/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "impl-tools-lib"
version = "0.9.1"
version = "0.10.0"
authors = ["Diggory Hardy <[email protected]>"]
edition = "2021"
license = "MIT/Apache-2.0"
Expand Down
53 changes: 28 additions & 25 deletions lib/src/singleton.rs → lib/src/anon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,20 @@
// You may obtain a copy of the License in the LICENSE-APACHE file or at:
// https://www.apache.org/licenses/LICENSE-2.0

//! The `impl_anon!` macro

use crate::fields::{Field, Fields, FieldsNamed, FieldsUnnamed, StructStyle};
use crate::{IdentFormatter, Scope, ScopeItem};
use crate::scope::{Scope, ScopeItem};
use crate::IdentFormatter;
use proc_macro2::{Span, TokenStream};
use quote::{quote, ToTokens, TokenStreamExt};
use syn::token::{Brace, Colon, Comma, Eq, Paren, Semi};
use syn::{parse_quote, punctuated::Punctuated, spanned::Spanned};
use syn::{Attribute, GenericParam, Generics, Ident, ItemImpl, Member, Token, Type, TypePath};

/// A field of a [`Singleton`]
/// A field of a [`Anon`]
#[derive(Debug)]
pub struct SingletonField {
pub struct AnonField {
/// Field attributes
pub attrs: Vec<Attribute>,
/// Field visibility
Expand All @@ -32,13 +35,13 @@ pub struct SingletonField {
pub assignment: Option<(Eq, syn::Expr)>,
}

/// A struct with a single instantiation
/// Contents of `impl_anon!`
///
/// The singleton macro may be used to conveniently declare a struct's type,
/// The impl_anon macro may be used to conveniently declare a struct's type,
/// implementations and construct an instance.
/// This struct represents the macro's input.
#[derive(Debug)]
pub struct Singleton {
pub struct Anon {
/// Struct attributes
pub attrs: Vec<Attribute>,
/// `struct` token
Expand All @@ -50,14 +53,14 @@ pub struct Singleton {
/// Struct style: unit/tuple/regular
pub style: StructStyle,
/// Struct fields
pub fields: Punctuated<SingletonField, Comma>,
pub fields: Punctuated<AnonField, Comma>,
/// (Explicit) struct implementations
pub impls: Vec<ItemImpl>,
}

impl Singleton {
/// Convert to a [`SingletonScope`]
pub fn into_scope(mut self) -> SingletonScope {
impl Anon {
/// Convert to a [`AnonScope`]
pub fn into_scope(mut self) -> AnonScope {
let mut idfmt = IdentFormatter::new();

let mut fields = Punctuated::<Field, Comma>::new();
Expand Down Expand Up @@ -221,7 +224,7 @@ impl Singleton {
let scope = Scope {
attrs: self.attrs,
vis: syn::Visibility::Inherited,
ident: parse_quote! { _Singleton },
ident: parse_quote! { _Anon },
generics: self.generics,
item: ScopeItem::Struct {
token: self.token,
Expand All @@ -232,7 +235,7 @@ impl Singleton {
generated: vec![],
};

SingletonScope(scope, field_val_toks)
AnonScope(scope, field_val_toks)
}
}

Expand All @@ -243,21 +246,21 @@ impl Singleton {
///
/// Tokens may be generated by [`Self::expand`].
#[derive(Debug)]
pub struct SingletonScope(Scope, TokenStream);
pub struct AnonScope(Scope, TokenStream);

impl std::ops::Deref for SingletonScope {
impl std::ops::Deref for AnonScope {
type Target = Scope;
fn deref(&self) -> &Scope {
&self.0
}
}
impl std::ops::DerefMut for SingletonScope {
impl std::ops::DerefMut for AnonScope {
fn deref_mut(&mut self) -> &mut Scope {
&mut self.0
}
}

impl SingletonScope {
impl AnonScope {
/// Generate the [`TokenStream`]
///
/// This is a convenience function. It is valid to, instead, (1) call
Expand All @@ -269,7 +272,7 @@ impl SingletonScope {
}
}

impl ToTokens for SingletonScope {
impl ToTokens for AnonScope {
fn to_tokens(&self, tokens: &mut TokenStream) {
let scope = &self.0;
let field_val_toks = &self.1;
Expand All @@ -278,7 +281,7 @@ impl ToTokens for SingletonScope {
{
#scope

_Singleton {
_Anon {
#field_val_toks
}
}
Expand Down Expand Up @@ -389,7 +392,7 @@ mod parsing {
})
}

impl SingletonField {
impl AnonField {
fn check_is_fixed(ty: &Type, input_span: Span) -> Result<()> {
let is_fixed = match ty {
Type::ImplTrait(_) | Type::Infer(_) => false,
Expand Down Expand Up @@ -448,7 +451,7 @@ mod parsing {
Self::check_is_fixed(&ty, input.span())?;
}

Ok(SingletonField {
Ok(AnonField {
attrs,
vis,
ident,
Expand All @@ -471,7 +474,7 @@ mod parsing {
Self::check_is_fixed(&ty, input.span())?;
}

Ok(SingletonField {
Ok(AnonField {
attrs,
vis,
ident: None,
Expand All @@ -482,7 +485,7 @@ mod parsing {
}
}

impl Parse for Singleton {
impl Parse for Anon {
fn parse(input: ParseStream) -> Result<Self> {
let attrs = input.call(Attribute::parse_outer)?;
let token = input.parse::<Token![struct]>()?;
Expand All @@ -500,7 +503,7 @@ mod parsing {
if generics.where_clause.is_none() && lookahead.peek(Paren) {
let content;
let paren_token = parenthesized!(content in input);
fields = content.parse_terminated(SingletonField::parse_unnamed, Token![,])?;
fields = content.parse_terminated(AnonField::parse_unnamed, Token![,])?;

lookahead = input.lookahead1();
if lookahead.peek(Token![where]) {
Expand All @@ -517,7 +520,7 @@ mod parsing {
let content;
let brace_token = braced!(content in input);
style = StructStyle::Regular(brace_token);
fields = content.parse_terminated(SingletonField::parse_named, Token![,])?;
fields = content.parse_terminated(AnonField::parse_named, Token![,])?;
} else if lookahead.peek(Semi) {
style = StructStyle::Unit(input.parse()?);
fields = Punctuated::new();
Expand All @@ -530,7 +533,7 @@ mod parsing {
impls.push(parse_impl(None, input)?);
}

Ok(Singleton {
Ok(Anon {
attrs,
token,
generics,
Expand Down
4 changes: 3 additions & 1 deletion lib/src/autoimpl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
//! Implementation of the `#[autoimpl]` attribute

use crate::generics::{clause_to_toks, WhereClause};
use crate::{ForDeref, SimplePath};
use crate::SimplePath;
use proc_macro2::{Span, TokenStream as Toks};
use proc_macro_error::emit_error;
use quote::{quote, TokenStreamExt};
Expand All @@ -17,9 +17,11 @@ use syn::{
Token,
};

mod for_deref;
mod impl_misc;
mod impl_using;

pub use for_deref::ForDeref;
pub use impl_misc::*;
pub use impl_using::*;

Expand Down
File renamed without changes.
5 changes: 3 additions & 2 deletions lib/src/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@

use crate::fields::{Fields, FieldsNamed, FieldsUnnamed};
use crate::generics::{clause_to_toks, WhereClause};
use crate::{Scope, ScopeAttr, ScopeItem, SimplePath};
use crate::scope::{Scope, ScopeAttr, ScopeItem};
use crate::SimplePath;
use proc_macro2::{Span, TokenStream};
use proc_macro_error::emit_error;
use quote::quote;
Expand Down Expand Up @@ -189,7 +190,7 @@ impl Parse for ImplDefault {
/// Helper fn which can be passed to [`Scope::apply_attrs`]
///
/// This optionally matches [`AttrImplDefault`].
pub fn find_attr_impl_default(path: &syn::Path) -> Option<&'static dyn ScopeAttr> {
pub fn find_impl_default(path: &syn::Path) -> Option<&'static dyn ScopeAttr> {
AttrImplDefault
.path()
.matches(path)
Expand Down
4 changes: 2 additions & 2 deletions lib/src/fields.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ pub struct Field {
/// Optional field initializer.
///
/// This is considered legal input when parsing, but not legal output. An
/// attribute rule such as [`crate::AttrImplDefault`] must remove the
/// initializer before output is generated.
/// attribute rule such as [`AttrImplDefault`](crate::scope::AttrImplDefault)
/// must remove the initializer before output is generated.
pub assign: Option<(Token![=], Expr)>,
}

Expand Down
16 changes: 6 additions & 10 deletions lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,26 @@
#![allow(clippy::unnecessary_lazy_evaluations)]
#![allow(clippy::style)]

pub mod anon;
pub mod autoimpl;
mod default;
pub mod fields;
mod for_deref;
pub mod generics;
mod scope;
mod singleton;
pub mod scope;

pub use default::{find_attr_impl_default, AttrImplDefault, ImplDefault};
pub use for_deref::ForDeref;
pub use default::ImplDefault;
use proc_macro2::Span;
pub use scope::{Scope, ScopeAttr, ScopeItem};
pub use singleton::{Singleton, SingletonField, SingletonScope};
use syn::Ident;

/// Tool to make a formatted [`Ident`]
/// Tool to make a formatted [`Ident`](struct@Ident)
pub struct IdentFormatter(String);
impl IdentFormatter {
/// Construct a formatter
pub fn new() -> Self {
IdentFormatter(String::with_capacity(32))
}

/// Construct a new [`Ident`]
/// Construct a new [`Ident`](struct@Ident)
pub fn make(&mut self, args: std::fmt::Arguments, span: Span) -> Ident {
use std::fmt::Write;

Expand All @@ -46,7 +42,7 @@ impl IdentFormatter {
Ident::new(&self.0, span)
}

/// Construct a new [`Ident`], using [`Span::call_site`]
/// Construct a new [`Ident`](struct@Ident), using [`Span::call_site`]
///
/// # Example
///
Expand Down
4 changes: 4 additions & 0 deletions lib/src/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// You may obtain a copy of the License in the LICENSE-APACHE file or at:
// https://www.apache.org/licenses/LICENSE-2.0

//! The `impl_scope!` macro

use crate::{fields::Fields, SimplePath};
use proc_macro2::{Span, TokenStream};
use proc_macro_error::emit_error;
Expand All @@ -15,6 +17,8 @@ use syn::{
Token, Type, Variant, Visibility,
};

pub use super::default::{find_impl_default, AttrImplDefault};

/// Attribute rule for [`Scope`]
///
/// Rules are matched via a path, e.g. `&["foo"]` matches `foo` and
Expand Down
Loading

0 comments on commit 3fe5057

Please sign in to comment.