1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
//! Adds `#[zoet]` macro to reduce boilerplate when implementing common traits.
//!
//! If you are sick of writing `impl Deref for Bar` etc. and it didn't compile because you confused
//! it with `AsRef`, had a hard-to-debug problem because you implemented `PartialOrd` and
//! mistakenly thought that deriving `Ord` would do the sane thing, and/or you would rather just
//! implement these core traits as regular methods in your `impl Bar` like lesser languages, this
//! crate is for you!
//!
//! It is superficially similar to the various derive macros such as [`derive_more`], except that
//! rather than generating traits based on the contents of a struct, it generates them based on
//! individual functions/methods. An example works better than a textual description ever would:
//!
//! ```
//! use core::cmp::Ordering;
//! use zoet::zoet;
//!
//! #[derive(Clone, Copy, Debug, Eq, PartialEq)]
//! struct Length(usize);
//! #[zoet]
//! impl Length {
//!     #[zoet(Default)] // generates `impl Default for Length`
//!     pub fn new() -> Self { Self(0) }
//!
//!     #[zoet(From)] // generates `From<usize> for Length`
//!     fn from_usize(value: usize) -> Self { Self(value) }
//!
//!     #[zoet(From)] // generates `From<Length> for usize`
//!     fn to_usize(self) -> usize { self.0 }
//!
//!     #[zoet(AsRef, Borrow, Deref)] // generates all of those
//!     fn as_usize(&self) -> &usize { &self.0 }
//!
//!     #[zoet(Add, AddAssign)] // generates `impl Add for Length` and `impl AddAssign for Length`
//!     fn add_assign(&mut self, rhs: Self) { self.0 += rhs.0; }
//!
//!     #[zoet(Ord, PartialOrd)] // you get the idea by now
//!     fn ord(&self, other: &Self) -> Ordering { self.0.cmp(&other.0) }
//! }
//!
//! let mut v = Length::default();
//! v += Length(1);
//! assert_eq!(v + Length(2), Length(3));
//! v += Length(4);
//! assert_eq!(v, Length(5));
//! assert_eq!(Length::from(v), Length(5));
//! ```
//!
//! Due to limitations in macro processing, you must add `#[zoet]` to your struct's impl block so
//! that the self type of its methods can be determined. This is obviously not necessary (or
//! possible) for free functions as they don't have a self type.
//!
//! Transformations for most traits in the standard library are provided. Omitted are those which
//! are just marker traits (there's no code to generate), those which require multiple functions,
//! and some which don't quite seem worth it. The current list is as follows:
//!
//! * `core::borrow`: `Borrow`, `BorrowMut`.
//! * `std::borrow`/`alloc::borrow`: `ToOwned`.
//! * `core::clone`: `Clone`.
//! * `core::cmp`: `Ord`, `PartialEq`, `PartialOrd`.
//! * `core::convert`: `AsMut`, `AsRef`, `From`, `Into`, `TryFrom`, `TryInto`.
//! * `core::default`: `Default`.
//! * `core::fmt`: `Debug`, `Display`, `Write` (implements the `write_str` method).
//! * `core::iterator`: `FromIterator`, `Iterator` (implements the `next` method).
//! * `core::ops`: `Deref`, `DerefMut`, `Drop`, `Index`, `IndexMut`, plus all arithmetic and bit
//! ops and assignment variants such as `Add` and `AddAssign`.
//! *`core::str`: `FromStr`.
//! * `std::string`/`alloc::string`: `ToString`.
//!
//! These traits normally just include the trait boilerplate and forward the arguments to your
//! method, however there are a couple of special cases which reduce boilerplate further:
//!
//! * `PartialOrd` can also be applied to an `Ord`-shaped function, in which case it wraps the
//! result with `Some()` to make it fit. This allows you to do `#zoet[(Ord, PartialOrd)]` to
//! implement both with the same function and avoid order-related bugs.
//!
//! * `Add` etc. can be applied to an `AddAssign`-shaped function, in which case it generates a
//! trivial implementation which mutates its `mut self` and returns it.
//!
//! Because macros run before type checking, they only knows the _names_ of the types, and not the
//! actual types. `zoet` prefers to be liberal and pass through types rather than attempt to parse
//! them, but we need to unpick the result type used by some traits such as `TryInto` into the
//! success and error types, or rather, the _names_ of the success and error types. As such, it
//! expects the result type to be called (or be a path ending in) `Result` or `Fallible`, and if
//! the second parameter is missing, the identifier `Error` is used. Idiomatic Rust code shouldn't
//! have a problem with this, but if you have unusual error-handling, you may trip over this.
//!
//! However, while this macro makes it easy to stamp out loads of core traits, don't go crazy but
//! consider each trait you add and whether there is a more suitable macro to do the job. The
//! example above generates `Default` based on `new()`, but since that function returns 0 which is
//! the default value anyway, it'd be better to `#derive(Default)` and implement `new()` in terms
//! of that. Similarly, its `Add` and `AddAssign` trait implementations just delegating to its
//! field's `Add` and `AddAssign` traits, and the can be completely eliminated by using
//! [`derive_more`] and deriving `Add` and `AddAssign` on the struct. And if your struct doesn't
//! satisfy `Borrow`'s invariants, you shouldn't unthinkingly do `#[zoet(AsRef, Borrow, Deref)]`.
//!
//! You are also reminded that [`cargo-expand`] exists, and can be used to inspect the expanded
//! text.
//!
//! [`cargo-expand`]: https://crates.io/crates/cargo-expand
//! [`derive_more`]: https://crates.io/crates/derive_more

extern crate alloc;
/// Re-exports of [`alloc`] traits so [`zoet`](crate)-generated code does not require `extern crate
/// alloc`.
pub mod traits {
    pub use ::alloc::{borrow::ToOwned, string::ToString};
}

pub use zoet_macro::zoet;