Skip to main content

internity_macros/
lib.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4#![cfg_attr(docsrs, feature(doc_cfg))]
5#![cfg_attr(coverage_nightly, feature(coverage_attribute))]
6
7//! Derive macros for interner-aware serialization and deserialization in
8//! [`internity`](https://docs.rs/internity).
9//!
10//! The [`DeserializeIn`](https://docs.rs/internity/latest/internity/derive.DeserializeIn.html)
11//! and [`SerializeIn`](https://docs.rs/internity/latest/internity/derive.SerializeIn.html)
12//! derives thread a reader or lexicon through Serde so [`Sym`] fields are
13//! encoded and decoded through the interner.
14//!
15//! [`Sym`]: https://docs.rs/internity/latest/internity/struct.Sym.html
16
17use proc_macro::TokenStream;
18use syn::{Path, parse_quote};
19
20/// Derive interner-aware deserialization for a struct.
21///
22/// The macro generates an implementation of `internity::de::DeserializeIn`,
23/// threading the interner through Serde so `Sym` fields are decoded through it.
24///
25/// # Supported shapes
26///
27/// Non-generic structs only: named-field, tuple, newtype, and unit structs, plus
28/// `#[serde(transparent)]` newtypes. Enums, unions, and generic types are
29/// rejected with a compile error.
30///
31/// # Attributes
32///
33/// * `#[internity(crate = "path")]` on the container renames the `internity`
34///   crate root (for re-exports or renamed dependencies).
35/// * `#[internity(via_serde)]` on a field decodes it with its ordinary
36///   [`serde::Deserialize`](https://docs.rs/serde) implementation instead of the
37///   interner-aware path.
38/// * Container `#[serde(...)]` attributes honored: `rename`, `rename_all`,
39///   `deny_unknown_fields`, `default`, `transparent`, and `expecting`.
40/// * Field `#[serde(...)]` attributes honored: `rename`, `alias`, `default`,
41///   `skip`/`skip_deserializing`, and `with`/`deserialize_with`.
42///
43/// # Rejected attributes
44///
45/// `#[serde(tag/content/untagged/remote)]` are rejected on any container because
46/// they change the wire shape in ways the interner-aware codegen cannot honor.
47/// Because this derive controls the deserialize direction, `#[serde(from)]` and
48/// `#[serde(try_from)]` are also rejected; `#[serde(into)]` is ignored (it only
49/// affects serialization).
50#[proc_macro_derive(DeserializeIn, attributes(internity, serde))]
51#[cfg_attr(test, mutants::skip)] // `proc_macro::TokenStream` is only usable by rustc.
52#[cfg_attr(coverage_nightly, coverage(off))]
53pub fn derive_deserialize_in(input: TokenStream) -> TokenStream {
54    let root_path: Path = parse_quote!(::internity);
55    internity_macros_impl::derive_deserialize_in(input.into(), &root_path).into()
56}
57
58/// Derive interner-aware serialization for a struct.
59///
60/// The macro generates an implementation of `internity::se::SerializeIn`,
61/// threading a reader through Serde so `Sym` fields are encoded through it.
62///
63/// # Supported shapes
64///
65/// Non-generic structs only: named-field, tuple, newtype, and unit structs, plus
66/// `#[serde(transparent)]` newtypes. Enums, unions, and generic types are
67/// rejected with a compile error.
68///
69/// # Attributes
70///
71/// * `#[internity(crate = "path")]` on the container renames the `internity`
72///   crate root (for re-exports or renamed dependencies).
73/// * `#[internity(via_serde)]` on a field encodes it with its ordinary
74///   [`serde::Serialize`](https://docs.rs/serde) implementation instead of the
75///   interner-aware path.
76/// * Container `#[serde(...)]` attributes honored: `rename`, `rename_all`,
77///   `transparent`, and their `serialize_`-prefixed forms.
78/// * Field `#[serde(...)]` attributes honored: `rename`, `skip`/
79///   `skip_serializing`, and `serialize_with`.
80///
81/// # Rejected attributes
82///
83/// `#[serde(tag/content/untagged/remote)]` are rejected on any container because
84/// they change the wire shape in ways the interner-aware codegen cannot honor.
85/// Because this derive controls the serialize direction, `#[serde(into)]` is
86/// rejected; `#[serde(from)]` and `#[serde(try_from)]` are ignored (they only
87/// affect deserialization). `#[serde(skip_serializing_if)]` is rejected because
88/// the interner-aware encoder cannot evaluate the predicate mid-stream.
89#[proc_macro_derive(SerializeIn, attributes(internity, serde))]
90#[cfg_attr(test, mutants::skip)] // `proc_macro::TokenStream` is only usable by rustc.
91#[cfg_attr(coverage_nightly, coverage(off))]
92pub fn derive_serialize_in(input: TokenStream) -> TokenStream {
93    let root_path: Path = parse_quote!(::internity);
94    internity_macros_impl::derive_serialize_in(input.into(), &root_path).into()
95}