Skip to content

Commit e869902

Browse files
committed
Write docs
1 parent 46a195b commit e869902

File tree

3 files changed

+330
-3
lines changed

3 files changed

+330
-3
lines changed

.config/topic.dic

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1-
7
1+
11
2+
Changelog
3+
CHANGELOG
24
destructure/G
35
enum/S
46
FQS
7+
io
58
MSRV
9+
std's
610
struct/S
711
TODO
812
tuple

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Changelog
2+
All notable changes to this project will be documented in this file.
3+
4+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6+
7+
## [Unreleased]
8+
9+
## [1.0.0-rc.1] - 2021-12-08
10+
### Added
11+
- Initial release.
12+
13+
[1.0.0-rc.1]: https://github.com/ModProg/derive-where/releases/tag/v1.0.0-rc.1

src/lib.rs

Lines changed: 312 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,295 @@
11
#![deny(unsafe_code)]
22
#![cfg_attr(feature = "nightly", feature(allow_internal_unstable))]
3+
#![allow(clippy::tabs_in_doc_comments)]
34
#![warn(clippy::cargo, clippy::missing_docs_in_private_items)]
45
#![cfg_attr(doc, warn(rustdoc::all), allow(rustdoc::missing_doc_code_examples))]
56

6-
//! TODO
7+
//! ## Description
8+
//!
9+
//! Derive macro to simplify deriving standard and other traits with custom
10+
//! generic type bounds.
11+
//!
12+
//! ## Usage
13+
//!
14+
//! ```rust
15+
//! # use std::marker::PhantomData;
16+
//! # use derive_where::DeriveWhere;
17+
//! #[derive(DeriveWhere)]
18+
//! #[derive_where(Clone, Debug)]
19+
//! struct Example<T>(PhantomData<T>);
20+
//! ```
21+
//!
22+
//! This will generate trait implementations for `Example` with any `T`,
23+
//! compared with std's derives, which would only implement these traits with
24+
//! `T: Trait` bound to the corresponding trait.
25+
//!
26+
//! In addition, the following convenience options are available:
27+
//!
28+
//! ### Generic type bounds
29+
//!
30+
//! ```
31+
//! # use std::marker::PhantomData;
32+
//! # use derive_where::DeriveWhere;
33+
//! #[derive(DeriveWhere)]
34+
//! #[derive_where(Clone; T)]
35+
//! struct Example<T, U>(T, PhantomData<U>);
36+
//! ```
37+
//!
38+
//! Separating the list of trait with a semi-colon, types to bind to can be
39+
//! specified. This will bind implementation for `Example` to `T: Trait`.
40+
//!
41+
//! ```
42+
//! # use std::marker::PhantomData;
43+
//! # use derive_where::DeriveWhere;
44+
//! trait Super: Clone {}
45+
//!
46+
//! #[derive(DeriveWhere)]
47+
//! #[derive_where(Clone; T: Super)]
48+
//! struct Example<T>(PhantomData<T>);
49+
//! ```
50+
//!
51+
//! This will bind implementation for `Example` to `T: Super`. But more complex
52+
//! trait bounds are possible:
53+
//!
54+
//! ```
55+
//! # use std::marker::PhantomData;
56+
//! # use derive_where::DeriveWhere;
57+
//! trait Trait {
58+
//! type Type;
59+
//! }
60+
//!
61+
//! struct Impl;
62+
//!
63+
//! impl Trait for Impl {
64+
//! type Type = i32;
65+
//! }
66+
//!
67+
//! #[derive(DeriveWhere)]
68+
//! #[derive_where(Clone; T::Type)]
69+
//! struct Example<T: Trait>(T::Type);
70+
//! ```
71+
//!
72+
//! This will bind implementation for `Example` to `T::Type: Super`. Any
73+
//! combination of options listed here can be used to satisfy a specific
74+
//! constrain.
75+
//!
76+
//! It is also possible to use two separate constrain specification when
77+
//! required:
78+
//!
79+
//! ```
80+
//! # use std::marker::PhantomData;
81+
//! # use derive_where::DeriveWhere;
82+
//! #[derive(DeriveWhere)]
83+
//! #[derive_where(Clone; T)]
84+
//! #[derive_where(Debug; U)]
85+
//! struct Example<T, U>(PhantomData<T>, PhantomData<U>);
86+
//! ```
87+
//!
88+
//! ### Enum default
89+
//!
90+
//! Deriving [`Default`] on an enum is not possible in Rust at the moment.
91+
//! Derive-where allows this with a `default` attribute:
92+
//!
93+
//! ```
94+
//! # use std::marker::PhantomData;
95+
//! # use derive_where::DeriveWhere;
96+
//! #[derive(DeriveWhere)]
97+
//! #[derive_where(Default)]
98+
//! enum Example<T> {
99+
//! #[derive_where(default)]
100+
//! A(PhantomData<T>),
101+
//! }
102+
//! ```
103+
//!
104+
//! ### Skipping fields
105+
//!
106+
//! With a `skip` or `skip_inner` attribute fields can be skipped for traits
107+
//! that allow it, which are: [`Debug`], [`Hash`], [`Ord`], [`PartialOrd`],
108+
//! [`PartialEq`] and [`Zeroize`].
109+
//!
110+
//! ```rust
111+
//! # use std::marker::PhantomData;
112+
//! # use derive_where::DeriveWhere;
113+
//! #[derive(DeriveWhere)]
114+
//! #[derive_where(Debug, PartialEq; T)]
115+
//! struct Example<T>(#[derive_where(skip)] T);
116+
//!
117+
//! assert_eq!(format!("{:?}", Example(42)), "Example");
118+
//! assert_eq!(Example(42), Example(0));
119+
//! ```
120+
//!
121+
//! It is also possible to skip all fields in an item or variant if desired:
122+
//!
123+
//! ```rust
124+
//! # use std::marker::PhantomData;
125+
//! # use derive_where::DeriveWhere;
126+
//! #[derive(DeriveWhere)]
127+
//! #[derive_where(Debug)]
128+
//! #[derive_where(skip_inner)]
129+
//! struct StructExample<T>(T);
130+
//!
131+
//! assert_eq!(format!("{:?}", StructExample(42)), "StructExample");
132+
//!
133+
//! #[derive(DeriveWhere)]
134+
//! #[derive_where(Debug)]
135+
//! enum EnumExample<T> {
136+
//! #[derive_where(skip_inner)]
137+
//! A(T),
138+
//! }
139+
//!
140+
//! assert_eq!(format!("{:?}", EnumExample::A(42)), "A");
141+
//! ```
142+
//!
143+
//! Selective skipping of fields for certain traits is also an option, both in
144+
//! `skip` and `skip_inner`:
145+
//!
146+
//! ```rust
147+
//! # use std::marker::PhantomData;
148+
//! # use derive_where::DeriveWhere;
149+
//! #[derive(DeriveWhere)]
150+
//! #[derive_where(Debug, PartialEq)]
151+
//! #[derive_where(skip_inner(Debug))]
152+
//! struct Example<T>(i32, PhantomData<T>);
153+
//!
154+
//! assert_eq!(format!("{:?}", Example(42, PhantomData::<()>)), "Example");
155+
//! assert_ne!(
156+
//! Example(42, PhantomData::<()>),
157+
//! Example(0, PhantomData::<()>)
158+
//! );
159+
//! ```
160+
//!
161+
//! ### `Zeroize` options
162+
//!
163+
//! [`Zeroize`] has three options:
164+
//! - `crate`: an item-level option which specifies a path to the `zeroize`
165+
//! crate in case of a re-export or rename.
166+
//! - `drop`: an item-level option which implements [`Drop`] and uses
167+
//! [`Zeroize`] to erase all data from memory.
168+
//! - `fqs`: a field -level option which will use fully-qualified-syntax instead
169+
//! of calling the [`zeroize`] method on `self` directly. This is to avoid
170+
//! ambiguity between another method also called `zeroize`.
171+
//!
172+
//! ```
173+
//! # use std::marker::PhantomData;
174+
//! # use derive_where::DeriveWhere;
175+
//! # use zeroize_::Zeroize;
176+
//! # // Fake `Zeroize` implementation because this crate doesn't have access to
177+
//! # // the zeroize crate because of MSRV.
178+
//! # mod zeroize_ {
179+
//! # pub trait Zeroize {
180+
//! # fn zeroize(&mut self);
181+
//! # }
182+
//! # impl Zeroize for i32 {
183+
//! # fn zeroize(&mut self) {
184+
//! # *self = 0;
185+
//! # }
186+
//! # }
187+
//! # }
188+
//! #[derive(DeriveWhere)]
189+
//! #[derive_where(Zeroize(crate = "zeroize_", drop))]
190+
//! struct Example(#[derive_where(Zeroize(fqs))] i32);
191+
//!
192+
//! impl Example {
193+
//! // If we didn't specify the `fqs` option, this would lead to a compile
194+
//! //error because of method ambiguity.
195+
//! fn zeroize(&mut self) {
196+
//! self.0 = 1;
197+
//! }
198+
//! }
199+
//!
200+
//! let mut test = Example(42);
201+
//!
202+
//! // Will call the struct method.
203+
//! test.zeroize();
204+
//! assert_eq!(test.0, 1);
205+
//!
206+
//! // WIll call the `Zeroize::zeroize` method.
207+
//! Zeroize::zeroize(&mut test);
208+
//! assert_eq!(test.0, 0);
209+
//! ```
210+
//!
211+
//! ### Supported traits
212+
//!
213+
//! The following traits can be derived with derive-where:
214+
//! - [`Clone`]
215+
//! - [`Copy`]
216+
//! - [`Debug`]
217+
//! - [`Default`]
218+
//! - [`Eq`]
219+
//! - [`Hash`]
220+
//! - [`Ord`]
221+
//! - [`PartialEq`]
222+
//! - [`PartialOrd`]
223+
//! - [`Zeroize`]: Only available with the `zeroize` crate feature.
224+
//!
225+
//! ### Supported items
226+
//!
227+
//! Structs, tuple structs, unions and enums are supported. Derive-where tries
228+
//! it's best to discourage usage that could be covered by std's `derive`. For
229+
//! example unit structs and enums only containing unit variants aren't
230+
//! supported.
231+
//!
232+
//! Unions can only implement [`Clone`] and [`Copy`].
233+
//!
234+
//! ### `no_std` support
235+
//!
236+
//! `no_std` support is provided by default.
237+
//!
238+
//! ## Crate features
239+
//!
240+
//! - `nightly`: Implements [`Ord`] and [`PartialOrd`] with the help of
241+
//! [`core::intrinsics::discriminant_value`], which is what Rust does by
242+
//! default too. Without this feature [`transmute`](core::mem::transmute) is
243+
//! used to convert [`Discriminant`](core::mem::Discriminant) to a [`i32`],
244+
//! which is the underlying type.
245+
//! - `safe`: Implements [`Ord`] and [`PartialOrd`] manually. This is much
246+
//! slower, but might be preferred if you don't trust derive-where. It also
247+
//! replaces all cases of [`core::hint::unreachable_unchecked`] in [`Ord`],
248+
//! [`PartialEq`] and [`PartialOrd`], which is what std uses, with
249+
//! [`unreachable`].
250+
//! - `zeroize`: Allows deriving [`Zeroize`].
251+
//!
252+
//! ## MSRV
253+
//!
254+
//! The current MSRV is 1.34 and is being checked by the CI. A change will be
255+
//! accompanied by a minor version bump. If MSRV is important to you, use
256+
//! `derive-where = "~1.x"` to pin a specific minor version to your crate.
257+
//!
258+
//! ## Alternatives
259+
//!
260+
//! [derivative](https://crates.io/crates/derivative)
261+
//! ([![Crates.io](https://img.shields.io/crates/v/derivative.svg)](https://crates.io/crates/derivative))
262+
//! is a great alternative with many options. Notably it has no `no_std`
263+
//! support.
264+
//!
265+
//! ## Changelog
266+
//!
267+
//! See the [CHANGELOG] file for details.
268+
//!
269+
//! ## License
270+
//!
271+
//! Licensed under either of
272+
//!
273+
//! - Apache License, Version 2.0 ([LICENSE-APACHE] or <http://www.apache.org/licenses/LICENSE-2.0>)
274+
//! - MIT license ([LICENSE-MIT] or <http://opensource.org/licenses/MIT>)
275+
//!
276+
//! at your option.
277+
//!
278+
//! ### Contribution
279+
//!
280+
//! Unless you explicitly state otherwise, any contribution intentionally
281+
//! submitted for inclusion in the work by you, as defined in the Apache-2.0
282+
//! license, shall be dual licensed as above, without any additional terms or
283+
//! conditions.
284+
//!
285+
//! [CHANGELOG]: https://github.com/getsentry/sentry-native/blob/main/CHANGELOG
286+
//! [LICENSE-MIT]: https://github.com/getsentry/sentry-native/blob/main/LICENSE-MIT
287+
//! [LICENSE-APACHE]: https://github.com/getsentry/sentry-native/blob/main/LICENSE-APACHE
288+
//! [`Debug`]: core::fmt::Debug
289+
//! [`Default`]: core::default::Default
290+
//! [`Hash`]: core::hash::Hash
291+
//! [`Zeroize`]: https://docs.rs/zeroize/latest/zeroize/trait.Zeroize.html
292+
//! [`zeroize`]: https://docs.rs/zeroize/latest/zeroize/trait.Zeroize.html#tymethod.zeroize
7293
8294
// MSRV: needed to support a lower MSRV.
9295
extern crate proc_macro;
@@ -39,7 +325,31 @@ use self::{
39325
/// Token used for attributes.
40326
const DERIVE_WHERE: &str = "derive_where";
41327

42-
/// TODO
328+
/// Item-level options:
329+
/// - `#[derive_where(Clone, ..; T, ..)]`: Specify traits to implement and
330+
/// optionally bounds.
331+
/// - `#[derive_where(Zeroize(crate = "path"))]`: Specify path to [`Zeroize`]
332+
/// trait.
333+
/// - `#[derive_where(Zeroize(drop))]`: Implement [`Drop`] with [`Zeroize`].
334+
/// - `#[derive_where(skip_inner(Clone, ..))]`: Skip all fields in the item.
335+
/// Optionally specify traits to constrain skipping fields. Only works for
336+
/// structs, for enums use this on the variant-level.
337+
///
338+
/// Variant-level options:
339+
/// - `#[derive_where(default)]`: Uses this variant as the default for the
340+
/// [`Default`](core::default::Default) implementation.
341+
/// - `#[derive_where(skip_inner(Clone, ..))]`: Skip all fields in this variant.
342+
/// Optionally specify traits to constrain skipping fields.
343+
///
344+
/// Field-level options:
345+
/// - `#[derive_where(skip(Clone, ...))]`: Skip field. Optionally specify traits
346+
/// to constrain skipping field.
347+
/// - `#[derive_where(Zeroize(fqs))]`: Use fully-qualified-syntax when
348+
/// implementing [`Zeroize`].
349+
///
350+
/// See the [crate](crate) level description for more details.
351+
///
352+
/// [`Zeroize`]: https://docs.rs/zeroize/latest/zeroize/trait.Zeroize.html
43353
#[proc_macro_derive(DeriveWhere, attributes(derive_where))]
44354
#[cfg_attr(feature = "nightly", allow_internal_unstable(core_intrinsics))]
45355
pub fn derive_where(input: proc_macro::TokenStream) -> proc_macro::TokenStream {

0 commit comments

Comments
 (0)