chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

View File

@@ -0,0 +1,73 @@
use darling::{FromDeriveInput, FromMeta};
#[derive(FromMeta, PartialEq, Eq, Debug)]
enum Volume {
Whisper,
Talk,
Shout,
}
/// A more complex example showing the ability to skip at a field or struct
/// level while still tracking which type parameters need to be bounded.
/// This can be seen by expanding this example using `cargo expand`.
#[derive(FromMeta)]
#[allow(dead_code)]
enum Emphasis<T> {
Constant(Volume),
Variable(darling::util::PathList),
#[darling(skip)]
PerPhoneme(Option<T>),
Strided {
#[darling(skip)]
step: Vec<T>,
#[darling(multiple)]
volume: Vec<Volume>,
},
}
#[derive(FromDeriveInput)]
#[darling(attributes(speak))]
struct SpeakingOptions<T, U> {
max_volume: U,
#[darling(skip, default)]
additional_data: Vec<T>,
}
#[derive(Default)]
struct Phoneme {
#[allow(dead_code)]
first: String,
}
// This is probably the holy grail for `darling`'s own internal use-case:
// Auto-apply `Default` bound to skipped *field* types in `where` clause.
impl<T, U> Default for SpeakingOptions<T, U>
where
Vec<T>: Default,
U: Default,
{
fn default() -> Self {
Self {
max_volume: Default::default(),
additional_data: Default::default(),
}
}
}
fn main() {
let derive_input = syn::parse_str(
r#"
#[derive(Speak)]
#[speak(max_volume = "shout")]
enum HtmlElement {
Div(String)
}
"#,
)
.unwrap();
let parsed: SpeakingOptions<Phoneme, Volume> =
FromDeriveInput::from_derive_input(&derive_input).unwrap();
assert_eq!(parsed.max_volume, Volume::Shout);
assert_eq!(parsed.additional_data.len(), 0);
}

View File

@@ -0,0 +1,175 @@
// The use of fields in debug print commands does not count as "used",
// which causes the fields to trigger an unwanted dead code warning.
#![allow(dead_code)]
//! This example shows how to do struct and field parsing using darling.
use darling::{ast, FromDeriveInput, FromField, FromMeta};
use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use syn::parse_str;
/// A speaking volume. Deriving `FromMeta` will cause this to be usable
/// as a string value for a meta-item key.
#[derive(Debug, Clone, Copy, FromMeta)]
#[darling(default)]
enum Volume {
Normal,
Whisper,
Shout,
}
impl Default for Volume {
fn default() -> Self {
Volume::Normal
}
}
/// Support parsing from a full derive input. Unlike FromMeta, this isn't
/// composable; each darling-dependent crate should have its own struct to handle
/// when its trait is derived.
#[derive(Debug, FromDeriveInput)]
// This line says that we want to process all attributes declared with `my_trait`,
// and that darling should panic if this receiver is given an enum.
#[darling(attributes(my_trait), supports(struct_any))]
struct MyInputReceiver {
/// The struct ident.
ident: syn::Ident,
/// The type's generics. You'll need these any time your trait is expected
/// to work with types that declare generics.
generics: syn::Generics,
/// Receives the body of the struct or enum. We don't care about
/// struct fields because we previously told darling we only accept structs.
data: ast::Data<(), MyFieldReceiver>,
/// The Input Receiver demands a volume, so use `Volume::Normal` if the
/// caller doesn't provide one.
#[darling(default)]
volume: Volume,
}
impl ToTokens for MyInputReceiver {
fn to_tokens(&self, tokens: &mut TokenStream) {
let MyInputReceiver {
ref ident,
ref generics,
ref data,
volume,
} = *self;
let (imp, ty, wher) = generics.split_for_impl();
let fields = data
.as_ref()
.take_struct()
.expect("Should never be enum")
.fields;
// Generate the format string which shows each field and its name
let fmt_string = fields
.iter()
.enumerate()
.map(|(i, f)| {
// We have to preformat the ident in this case so we can fall back
// to the field index for unnamed fields. It's not easy to read,
// unfortunately.
format!(
"{} = {{}}",
f.ident
.as_ref()
.map(|v| format!("{}", v))
.unwrap_or_else(|| format!("{}", i))
)
})
.collect::<Vec<_>>()
.join(", ");
// Generate the actual values to fill the format string.
let field_list = fields
.into_iter()
.enumerate()
.map(|(i, f)| {
let field_volume = f.volume.unwrap_or(volume);
// This works with named or indexed fields, so we'll fall back to the index so we can
// write the output as a key-value pair.
let field_ident = f.ident
.as_ref()
.map(|v| quote!(#v))
.unwrap_or_else(|| {
let i = syn::Index::from(i);
quote!(#i)
});
match field_volume {
Volume::Normal => quote!(self.#field_ident),
Volume::Shout => {
quote!(::std::string::ToString::to_string(&self.#field_ident).to_uppercase())
}
Volume::Whisper => {
quote!(::std::string::ToString::to_string(&self.#field_ident).to_lowercase())
}
}
})
.collect::<Vec<_>>();
tokens.extend(quote! {
impl #imp Speak for #ident #ty #wher {
fn speak(&self, writer: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(writer, #fmt_string, #(#field_list),*)
}
}
});
}
}
#[derive(Debug, FromField)]
#[darling(attributes(my_trait))]
struct MyFieldReceiver {
/// Get the ident of the field. For fields in tuple or newtype structs or
/// enum bodies, this can be `None`.
ident: Option<syn::Ident>,
/// This magic field name pulls the type from the input.
ty: syn::Type,
/// We declare this as an `Option` so that during tokenization we can write
/// `field.volume.unwrap_or(derive_input.volume)` to facilitate field-level
/// overrides of struct-level settings.
///
/// Because this field is an `Option`, we don't need to include `#[darling(default)]`
volume: Option<Volume>,
}
fn main() {
let input = r#"#[derive(MyTrait)]
#[my_trait(volume = "shout")]
pub struct Foo {
#[my_trait(volume = "whisper")]
bar: bool,
baz: i64,
}"#;
let parsed = parse_str(input).unwrap();
let receiver = MyInputReceiver::from_derive_input(&parsed).unwrap();
let tokens = quote!(#receiver);
println!(
r#"
INPUT:
{}
PARSED AS:
{:?}
EMITS:
{}
"#,
input, receiver, tokens
);
}

26
vendor/darling/examples/expr_with.rs vendored Normal file
View File

@@ -0,0 +1,26 @@
use darling::{util::parse_expr, FromDeriveInput, FromMeta};
use syn::{parse_quote, Expr};
#[derive(FromDeriveInput)]
#[darling(attributes(demo))]
pub struct Receiver {
#[darling(with = parse_expr::preserve_str_literal, map = Some)]
example1: Option<Expr>,
#[darling(
// A closure can be used in lieu of a path.
with = |m| Ok(String::from_meta(m)?.to_uppercase()),
default
)]
example2: String,
}
fn main() {
let input = Receiver::from_derive_input(&parse_quote! {
#[demo(example1 = test::path, example2 = "hello")]
struct Example;
})
.unwrap();
assert_eq!(input.example1, Some(parse_quote!(test::path)));
assert_eq!(input.example2, "HELLO".to_string());
}

View File

@@ -0,0 +1,85 @@
//! This example demonstrates techniques for performing custom error handling
//! in a derive-input receiver.
//!
//! 1. Using `darling::Result` as a carrier to preserve the error for later display
//! 1. Using `Result<T, syn::Meta>` to attempt a recovery in imperative code
//! 1. Using the `map` darling meta-item to post-process a field before returning
//! 1. Using the `and_then` darling meta-item to post-process the receiver before returning
use darling::{FromDeriveInput, FromMeta};
use syn::parse_str;
#[derive(Debug, FromDeriveInput)]
#[darling(attributes(my_trait), and_then = MyInputReceiver::autocorrect)]
pub struct MyInputReceiver {
/// This field must be present and a string or else parsing will panic.
#[darling(map = MyInputReceiver::make_string_shouty)]
name: String,
/// If this field fails to parse, the struct can still be built; the field
/// will contain the error. The consuming struct can then decide if this
/// blocks code generation. If so, panic or fail in `and_then`.
frequency: darling::Result<i64>,
/// If this field fails to parse, the struct can still be built; the field
/// will contain an `Err` with the original `syn::Meta`. This can be used
/// for alternate parsing attempts before panicking.
amplitude: Result<u64, syn::Meta>,
}
impl MyInputReceiver {
/// This function will be called by `darling` _after_ it's finished parsing the
/// `name` field but before initializing `name` with the resulting value. It's
/// a good place for transforms that are easiest to express on already-built
/// types.
fn make_string_shouty(s: String) -> String {
s.to_uppercase()
}
/// This function will be called by `darling` _after_ it's finished parsing the
/// input but before returning to the caller. This is a good place to initialize
/// skipped fields or to perform corrections that don't lend themselves to being
/// done elsewhere.
fn autocorrect(self) -> darling::Result<Self> {
let Self {
name,
frequency,
amplitude,
} = self;
// Amplitude doesn't have a sign, so if we received a negative number then
// we'll go ahead and make it positive.
let amplitude = match amplitude {
Ok(amp) => amp,
Err(mi) => (i64::from_meta(&mi)?).unsigned_abs(),
};
Ok(Self {
name,
frequency,
amplitude: Ok(amplitude),
})
}
}
fn main() {
let input = r#"#[derive(MyTrait)]
#[my_trait(name="Jon", amplitude = "-1", frequency = 1)]
pub struct Foo;"#;
let parsed = parse_str(input).unwrap();
let receiver = MyInputReceiver::from_derive_input(&parsed).unwrap();
println!(
r#"
INPUT:
{}
PARSED AS:
{:?}
"#,
input, receiver
);
}

View File

@@ -0,0 +1,79 @@
//! This example demonstrates:
//!
//! - The behavior of a derived `FromMeta` implementation for heterogeneous enums
//! (i.e. enums that include a mix of unit, newtype and struct variants).
//! - Using `#[darling(word)]` to specify a unit variant to use when a receiver field
//! is specified without a value (i.e. a unit variant to use for deriving the
//! `FromMeta::from_word` method).
//! - Using `#[darling(default)]` on a receiver field to fall back to `Default::default()`
//! for the enum's value when the receiver field is not specified by the caller.
use darling::{Error, FromDeriveInput, FromMeta};
use syn::parse_quote;
/// A playback volume.
#[derive(Debug, FromMeta, PartialEq, Eq)]
enum Volume {
Normal,
#[darling(word)]
Low,
High,
#[darling(rename = "dB")]
Decibels(u8),
}
impl Default for Volume {
fn default() -> Self {
Volume::Normal
}
}
#[derive(Debug, FromDeriveInput)]
#[darling(attributes(play))]
struct PlayReceiver {
#[darling(default)]
volume: Volume,
}
fn main() {
// `Default::default()` is used when `volume` is not specified.
let missing_volume = PlayReceiver::from_derive_input(&parse_quote! {
#[play]
struct Player;
})
.unwrap();
assert_eq!(Volume::Normal, missing_volume.volume);
// `#[darling(word)]` unit variant is used when `volume` is specified as a word with no value.
let empty_volume = PlayReceiver::from_derive_input(&parse_quote! {
#[play(volume)]
struct Player;
})
.unwrap();
assert_eq!(Volume::Low, empty_volume.volume);
// Specified `volume` value is used when provided.
let unit_variant_volume = PlayReceiver::from_derive_input(&parse_quote! {
#[play(volume(high))]
struct Player;
})
.unwrap();
assert_eq!(Volume::High, unit_variant_volume.volume);
let newtype_volume = PlayReceiver::from_derive_input(&parse_quote! {
#[play(volume(dB = 100))]
struct Player;
})
.unwrap();
assert_eq!(Volume::Decibels(100), newtype_volume.volume);
// Multiple `volume` values result in an error.
let err = PlayReceiver::from_derive_input(&parse_quote! {
#[play(volume(low, dB = 20))]
struct Player;
})
.unwrap_err();
assert_eq!(
err.to_string(),
Error::too_many_items(1).at("volume").to_string()
);
}

View File

@@ -0,0 +1,79 @@
//! Example showing potentially-nested meta item parsing with `darling::util::Override`.
//!
//! Based on https://stackoverflow.com/q/68046070/86381 by https://github.com/peterjoel
// The use of fields in debug print commands does not count as "used",
// which causes the fields to trigger an unwanted dead code warning.
#![allow(dead_code)]
use std::borrow::Cow;
use darling::{util::Override, FromDeriveInput, FromMeta};
use syn::{Ident, Path};
#[derive(Debug, FromDeriveInput)]
#[darling(attributes(myderive))]
struct MyDeriveInput {
ident: Ident,
/// We can infer the right "table" behavior for this derive, but we want the caller to be
/// explicit that they're expecting the inference behavior to avoid cluttering some hypothetical
/// database. Therefore this field is required, but can take word form or key-value form.
///
/// To make this field optional, we could add `#[darling(default)]`, or we could
/// wrap it in `Option` if the presence or absence of the word makes a difference.
table: Override<Table>,
}
impl MyDeriveInput {
fn table(&self) -> Cow<'_, Table> {
match &self.table {
Override::Explicit(value) => Cow::Borrowed(value),
Override::Inherit => Cow::Owned(Table {
name: self.ident.to_string(),
value: None,
}),
}
}
}
#[derive(Debug, Clone, FromMeta)]
struct Table {
name: String,
value: Option<Path>,
}
fn from_str(s: &str) -> darling::Result<MyDeriveInput> {
FromDeriveInput::from_derive_input(&syn::parse_str(s)?)
}
fn main() {
let missing = from_str(
r#"
#[derive(MyTrait)]
struct Foo(u64);
"#,
)
.unwrap_err();
let short_form = from_str(
r#"
#[derive(MyTrait)]
#[myderive(table)]
struct Foo(u64);
"#,
)
.unwrap();
let long_form = from_str(
r#"
#[derive(MyTrait)]
#[myderive(table(name = "Custom"))]
struct Foo(u64);
"#,
)
.unwrap();
println!("Error when missing: {}", missing);
println!("Short form: {:?}", short_form.table());
println!("Long form: {:?}", long_form.table());
}

View File

@@ -0,0 +1,61 @@
// The use of fields in debug print commands does not count as "used",
// which causes the fields to trigger an unwanted dead code warning.
#![allow(dead_code)]
use darling::{ast, util, FromDeriveInput, FromField};
use syn::{Ident, Type};
#[derive(Debug, FromField)]
#[darling(attributes(lorem))]
pub struct LoremField {
ident: Option<Ident>,
ty: Type,
#[darling(default)]
skip: bool,
}
#[derive(Debug, FromDeriveInput)]
#[darling(attributes(lorem), supports(struct_named))]
pub struct Lorem {
ident: Ident,
data: ast::Data<util::Ignored, LoremField>,
}
fn main() {
let good_input = r#"#[derive(Lorem)]
pub struct Foo {
#[lorem(skip)]
bar: bool,
baz: i64,
}"#;
let bad_input = r#"#[derive(Lorem)]
pub struct BadFoo(String, u32);"#;
let parsed = syn::parse_str(good_input).unwrap();
let receiver = Lorem::from_derive_input(&parsed).unwrap();
let wrong_shape_parsed = syn::parse_str(bad_input).unwrap();
let wrong_shape = Lorem::from_derive_input(&wrong_shape_parsed).expect_err("Shape was wrong");
println!(
r#"
INPUT:
{}
PARSED AS:
{:?}
BAD INPUT:
{}
PRODUCED ERROR:
{}
"#,
good_input, receiver, bad_input, wrong_shape
);
}