summaryrefslogtreecommitdiffstats
path: root/third_party/rust/smart-default
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/rust/smart-default
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/smart-default')
-rw-r--r--third_party/rust/smart-default/.cargo-checksum.json1
-rw-r--r--third_party/rust/smart-default/CHANGELOG.md59
-rw-r--r--third_party/rust/smart-default/Cargo.lock47
-rw-r--r--third_party/rust/smart-default/Cargo.toml34
-rw-r--r--third_party/rust/smart-default/LICENSE21
-rw-r--r--third_party/rust/smart-default/README.md39
-rw-r--r--third_party/rust/smart-default/examples/example.rs33
-rw-r--r--third_party/rust/smart-default/src/body_impl.rs158
-rw-r--r--third_party/rust/smart-default/src/default_attr.rs89
-rw-r--r--third_party/rust/smart-default/src/lib.rs73
-rw-r--r--third_party/rust/smart-default/src/util.rs21
-rw-r--r--third_party/rust/smart-default/tests/tests.rs170
12 files changed, 745 insertions, 0 deletions
diff --git a/third_party/rust/smart-default/.cargo-checksum.json b/third_party/rust/smart-default/.cargo-checksum.json
new file mode 100644
index 0000000000..c48bc2cde9
--- /dev/null
+++ b/third_party/rust/smart-default/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"CHANGELOG.md":"391b5ca7965b379588e8cdd0fdc76a2c6ac44603dd007ddfb9263dc4232b6eb4","Cargo.lock":"6060bc53da766a9073b1fd836699f99b2fc28a99bf15dbf9f213f6bce3008dba","Cargo.toml":"886220167526d72040ace0629cab35e9e7a2b22d76bb28c7332a2e9ab2e42db8","LICENSE":"f09111a2bf85257f1d098de0095ad77fd12649fbbe9a33c8a13e422848b601bb","README.md":"553e1508b8e7b3fc0afeb8636263169da6a85d92aa6605fbeada927f62e6a88e","examples/example.rs":"5ea8b9f063549e46e74a8b5e7079a14a8296d945536271d1be65400a9377218b","src/body_impl.rs":"d1e3a209037d43ad653fdf7628ad52c4b70eced8d03e5e7b12e4381de8eb642a","src/default_attr.rs":"89e721794c16da3dbf59fc71381cbff74b7c0b5a5805765306fdfda0a9615ec2","src/lib.rs":"ff620a9442205980f0445f1624dba132f710ba5fcaccd65b8d1493f8af232333","src/util.rs":"8c553bfcf7d8a7d7960a1c3e3517218648ab4bd3ec5144b972a623b98bff1427","tests/tests.rs":"2f847e22064723d70145db3dfeadfa5b14b0d58ba9bdc36ff0e46b7f52eba511"},"package":"0eb01866308440fc64d6c44d9e86c5cc17adfe33c4d6eed55da9145044d0ffc1"} \ No newline at end of file
diff --git a/third_party/rust/smart-default/CHANGELOG.md b/third_party/rust/smart-default/CHANGELOG.md
new file mode 100644
index 0000000000..07b4a571ad
--- /dev/null
+++ b/third_party/rust/smart-default/CHANGELOG.md
@@ -0,0 +1,59 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+
+## [Unreleased]
+
+## 0.7.1 - 2023-04-24
+### Fixed
+- Fixed bug where the macro fails on valid default expression that is also a
+ valid attribute meta because it was expecting the `_code` hack.
+
+## 0.7.0 - 2023-04-23
+### Changed
+- Update `syn` to version 2
+
+## 0.6.0 - 2019-12-13
+### Changed
+- Update `syn`, `quote` and `proc-macro2` versions to `1.*.*`.
+
+## 0.5.2 - 2019-04-13
+### Fixed
+- Omit linting of generated code by adding `#[automatically_derived]` attribute.
+
+## 0.5.1 - 2019-03-01
+### Fixed
+- Don't use a multi-pattern `if let`, as this unnecessarily requires version
+ 1.33.0 of Rust.
+
+## 0.5.0 - 2019-03-01
+### Changed
+- When the default is a string literal, strap an `.into()` after it to
+ automatically convert it to `String` when needed.
+
+## 0.4.0 - 2019-02-19
+### Added
+- `#[default(_code = "...")]` syntax for defaults that cannot be parsed as
+ attributes no matter what.
+
+## 0.3.0 - 2018-11-02
+### Changed
+- Require Rust 1.30+.
+- Use direct attribute value instead of having to wrap them in strings.
+- Moved the docs from the module level to the custom derive.
+
+### Added
+- `#[default(...)]` syntax in addition to `#[default = ...]`. This is required
+ to deal with some parsing limitations.
+
+## 0.2.0 - 2017-08-21
+### Added
+- Support generic types.
+- Generate doc for the trait impl that describes the default values.
+
+## 0.1.0 - 2017-08-18
+### Added
+- Custom derive `SmartDefault` for implementing the `Default` trait.
+- `#[default = ...]` attribute on fields for smart-default.
diff --git a/third_party/rust/smart-default/Cargo.lock b/third_party/rust/smart-default/Cargo.lock
new file mode 100644
index 0000000000..e797d66e01
--- /dev/null
+++ b/third_party/rust/smart-default/Cargo.lock
@@ -0,0 +1,47 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.56"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "smart-default"
+version = "0.7.1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
diff --git a/third_party/rust/smart-default/Cargo.toml b/third_party/rust/smart-default/Cargo.toml
new file mode 100644
index 0000000000..ae15d56ee7
--- /dev/null
+++ b/third_party/rust/smart-default/Cargo.toml
@@ -0,0 +1,34 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2021"
+name = "smart-default"
+version = "0.7.1"
+authors = ["IdanArye <idanarye@gmail.com>"]
+description = "Rust custom-derive macro for Default with more control on the fields"
+documentation = "https://idanarye.github.io/rust-smart-default/"
+readme = "README.md"
+keywords = ["default"]
+license = "MIT"
+repository = "https://github.com/idanarye/rust-smart-default"
+
+[lib]
+proc-macro = true
+
+[dependencies.proc-macro2]
+version = "1"
+
+[dependencies.quote]
+version = "1"
+
+[dependencies.syn]
+version = "2"
diff --git a/third_party/rust/smart-default/LICENSE b/third_party/rust/smart-default/LICENSE
new file mode 100644
index 0000000000..015f0b2fcc
--- /dev/null
+++ b/third_party/rust/smart-default/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017 Idan Arye
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/third_party/rust/smart-default/README.md b/third_party/rust/smart-default/README.md
new file mode 100644
index 0000000000..1ece6950c4
--- /dev/null
+++ b/third_party/rust/smart-default/README.md
@@ -0,0 +1,39 @@
+[![Build Status](https://github.com/idanarye/rust-smart-default/workflows/CI/badge.svg)](https://github.com/idanarye/rust-smart-default/actions)
+[![Latest Version](https://img.shields.io/crates/v/smart-default.svg)](https://crates.io/crates/smart-default)
+[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://idanarye.github.io/rust-smart-default/)
+
+# Rust SmartDefault
+
+Custom derive for automatically implementing the `Default` trait with customized default values:
+
+```rust
+use smart_default::SmartDefault;
+
+#[derive(SmartDefault)]
+enum Foo {
+ Bar,
+ #[default]
+ Baz {
+ #[default = 12]
+ a: i32,
+ b: i32,
+ #[default(Some(Default::default()))]
+ c: Option<i32>,
+ #[default(_code = "vec![1, 2, 3]")]
+ d: Vec<u32>,
+ #[default = "four"]
+ e: String,
+ },
+ Qux(i32),
+}
+
+assert!(Foo::default() == Foo::Baz {
+ a: 12,
+ b: 0,
+ c: Some(0),
+ d: vec![1, 2, 3],
+ e: "four".to_owned(),
+});
+```
+
+Requires Rust 1.30+ (for non-string values in attributes)
diff --git a/third_party/rust/smart-default/examples/example.rs b/third_party/rust/smart-default/examples/example.rs
new file mode 100644
index 0000000000..ee3473daca
--- /dev/null
+++ b/third_party/rust/smart-default/examples/example.rs
@@ -0,0 +1,33 @@
+use smart_default::SmartDefault;
+
+#[derive(PartialEq, SmartDefault, Debug)]
+#[allow(dead_code)]
+enum Foo {
+ Bar,
+ #[default]
+ Baz {
+ #[default(12)]
+ a: i32,
+ b: i32,
+ #[default(Some(Default::default()))]
+ c: Option<i32>,
+ #[default(_code = "vec![1, 2, 3]")]
+ d: Vec<u32>,
+ #[default = "four"]
+ e: String,
+ },
+ Qux(i32),
+}
+
+fn main() {
+ assert!(
+ Foo::default()
+ == Foo::Baz {
+ a: 12,
+ b: 0,
+ c: Some(0),
+ d: vec![1, 2, 3],
+ e: "four".to_owned(),
+ }
+ );
+}
diff --git a/third_party/rust/smart-default/src/body_impl.rs b/third_party/rust/smart-default/src/body_impl.rs
new file mode 100644
index 0000000000..09b80e56c3
--- /dev/null
+++ b/third_party/rust/smart-default/src/body_impl.rs
@@ -0,0 +1,158 @@
+use proc_macro2::TokenStream;
+
+use quote::quote;
+use syn::parse::Error;
+use syn::spanned::Spanned;
+use syn::DeriveInput;
+
+use crate::default_attr::{ConversionStrategy, DefaultAttr};
+use crate::util::find_only;
+
+pub fn impl_my_derive(input: &DeriveInput) -> Result<TokenStream, Error> {
+ let name = &input.ident;
+ let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
+
+ let (default_expr, doc) = match input.data {
+ syn::Data::Struct(ref body) => {
+ let (body_assignment, doc) = default_body_tt(&body.fields)?;
+ (
+ quote! {
+ #name #body_assignment
+ },
+ format!("Return `{}{}`", name, doc),
+ )
+ }
+ syn::Data::Enum(ref body) => {
+ let default_variant = find_only(body.variants.iter(), |variant| {
+ if let Some(meta) = DefaultAttr::find_in_attributes(&variant.attrs)? {
+ if meta.code.is_none() {
+ Ok(true)
+ } else {
+ Err(Error::new(
+ meta.code.span(),
+ "Attribute #[default] on variants should have no value",
+ ))
+ }
+ } else {
+ Ok(false)
+ }
+ })?
+ .ok_or_else(|| Error::new(input.span(), "No default variant"))?;
+ let default_variant_name = &default_variant.ident;
+ let (body_assignment, doc) = default_body_tt(&default_variant.fields)?;
+ (
+ quote! {
+ #name :: #default_variant_name #body_assignment
+ },
+ format!("Return `{}::{}{}`", name, default_variant_name, doc),
+ )
+ }
+ syn::Data::Union(_) => {
+ panic!()
+ }
+ };
+ Ok(quote! {
+ #[automatically_derived]
+ impl #impl_generics Default for #name #ty_generics #where_clause {
+ #[doc = #doc]
+ fn default() -> Self {
+ #default_expr
+ }
+ }
+ })
+}
+
+/// Return a token-tree for the default "body" - the part after the name that contains the values.
+/// That is, the `{ ... }` part for structs, the `(...)` part for tuples, and nothing for units.
+fn default_body_tt(body: &syn::Fields) -> Result<(TokenStream, String), Error> {
+ let mut doc = String::new();
+ use std::fmt::Write;
+ let body_tt = match body {
+ syn::Fields::Named(ref fields) => {
+ doc.push_str(" {");
+ let result = {
+ let field_assignments = fields
+ .named
+ .iter()
+ .map(|field| {
+ let field_name = field.ident.as_ref();
+ let (default_value, default_doc) = field_default_expr_and_doc(field)?;
+ write!(
+ &mut doc,
+ "\n {}: {},",
+ field_name.expect("field value in struct is empty"),
+ default_doc
+ )
+ .unwrap();
+ // let default_value = default_value.into_token_stream();
+ Ok(quote! { #field_name : #default_value })
+ })
+ .collect::<Result<Vec<_>, Error>>()?;
+ quote! {
+ {
+ #( #field_assignments ),*
+ }
+ }
+ };
+ if doc.ends_with(',') {
+ doc.pop();
+ doc.push('\n');
+ };
+ doc.push('}');
+ result
+ }
+ syn::Fields::Unnamed(ref fields) => {
+ doc.push('(');
+ let result = {
+ let field_assignments = fields
+ .unnamed
+ .iter()
+ .map(|field| {
+ let (default_value, default_doc) = field_default_expr_and_doc(field)?;
+ write!(&mut doc, "{}, ", default_doc).unwrap();
+ Ok(default_value)
+ })
+ .collect::<Result<Vec<TokenStream>, Error>>()?;
+ quote! {
+ (
+ #( #field_assignments ),*
+ )
+ }
+ };
+ if doc.ends_with(", ") {
+ doc.pop();
+ doc.pop();
+ };
+ doc.push(')');
+ result
+ }
+ &syn::Fields::Unit => quote! {},
+ };
+ Ok((body_tt, doc))
+}
+
+/// Return a default expression for a field based on it's `#[default = "..."]` attribute. Panic
+/// if there is more than one, of if there is a `#[default]` attribute without value.
+fn field_default_expr_and_doc(field: &syn::Field) -> Result<(TokenStream, String), Error> {
+ if let Some(default_attr) = DefaultAttr::find_in_attributes(&field.attrs)? {
+ let conversion_strategy = default_attr.conversion_strategy();
+ let field_value = default_attr.code.ok_or_else(|| {
+ Error::new(field.span(), "Expected #[default = ...] or #[default(...)]")
+ })?;
+
+ let field_value = match conversion_strategy {
+ ConversionStrategy::NoConversion => field_value,
+ ConversionStrategy::Into => quote!((#field_value).into()),
+ };
+
+ let field_doc = format!("{}", field_value);
+ Ok((field_value, field_doc))
+ } else {
+ Ok((
+ quote! {
+ Default::default()
+ },
+ "Default::default()".to_owned(),
+ ))
+ }
+}
diff --git a/third_party/rust/smart-default/src/default_attr.rs b/third_party/rust/smart-default/src/default_attr.rs
new file mode 100644
index 0000000000..ce871fd231
--- /dev/null
+++ b/third_party/rust/smart-default/src/default_attr.rs
@@ -0,0 +1,89 @@
+use proc_macro2::TokenStream;
+use quote::ToTokens;
+use syn::{parse::Error, MetaNameValue};
+
+use crate::util::find_only;
+
+#[derive(Debug, Clone, Copy)]
+pub enum ConversionStrategy {
+ NoConversion,
+ Into,
+}
+
+pub struct DefaultAttr {
+ pub code: Option<TokenStream>,
+ conversion_strategy: Option<ConversionStrategy>,
+}
+
+impl DefaultAttr {
+ pub fn find_in_attributes(attrs: &[syn::Attribute]) -> Result<Option<Self>, Error> {
+ if let Some(default_attr) =
+ find_only(attrs.iter(), |attr| Ok(attr.path().is_ident("default")))?
+ {
+ match &default_attr.meta {
+ syn::Meta::Path(_) => Ok(Some(Self {
+ code: None,
+ conversion_strategy: None,
+ })),
+ syn::Meta::List(meta) => {
+ // If the meta contains exactly (_code = "...") take the string literal as the
+ // expression
+ if let Ok(ParseCodeHack(code_hack)) = syn::parse(meta.tokens.clone().into()) {
+ Ok(Some(Self {
+ code: Some(code_hack),
+ conversion_strategy: Some(ConversionStrategy::NoConversion),
+ }))
+ } else {
+ Ok(Some(Self {
+ code: Some(meta.tokens.clone()),
+ conversion_strategy: None,
+ }))
+ }
+ }
+ syn::Meta::NameValue(MetaNameValue { value, .. }) => Ok(Some(Self {
+ code: Some(value.into_token_stream()),
+ conversion_strategy: None,
+ })),
+ }
+ } else {
+ Ok(None)
+ }
+ }
+
+ pub fn conversion_strategy(&self) -> ConversionStrategy {
+ if let Some(conversion_strategy) = self.conversion_strategy {
+ // Conversion strategy already set
+ return conversion_strategy;
+ }
+ let code = if let Some(code) = &self.code {
+ code
+ } else {
+ // #[default] - so no conversion (`Default::default()` already has the correct type)
+ return ConversionStrategy::NoConversion;
+ };
+ match syn::parse::<syn::Lit>(code.clone().into()) {
+ Ok(syn::Lit::Str(_)) | Ok(syn::Lit::ByteStr(_)) => {
+ // A string literal - so we need a conversion in case we need to make it a `String`
+ return ConversionStrategy::Into;
+ }
+ _ => {}
+ }
+ // Not handled by one of the rules, so we don't convert it to avoid causing trouble
+ ConversionStrategy::NoConversion
+ }
+}
+
+struct ParseCodeHack(TokenStream);
+
+impl syn::parse::Parse for ParseCodeHack {
+ fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
+ let ident: syn::Ident = input.parse()?;
+ if ident != "_code" {
+ return Err(Error::new(ident.span(), "Expected `_code`"));
+ }
+ input.parse::<syn::token::Eq>()?;
+ let code: syn::LitStr = input.parse()?;
+ let code: TokenStream = code.parse()?;
+ Ok(ParseCodeHack(code))
+ }
+}
diff --git a/third_party/rust/smart-default/src/lib.rs b/third_party/rust/smart-default/src/lib.rs
new file mode 100644
index 0000000000..360828f1ef
--- /dev/null
+++ b/third_party/rust/smart-default/src/lib.rs
@@ -0,0 +1,73 @@
+use syn::{parse_macro_input, DeriveInput};
+
+mod body_impl;
+mod default_attr;
+mod util;
+
+/// # Smart Default
+///
+/// This crate provides a custom derive for `SmartDefault`. `SmartDefault` is not a real trait -
+/// deriving it will actually `impl Default`. The difference from regular `#[derive(Default)]` is
+/// that `#[derive(SmartDefault)]` allows you to use `#[default = "..."]` attributes to customize
+/// the `::default()` method and to support `struct`s that don't have `Default` for all their
+/// fields - and even `enum`s!
+///
+/// # Examples
+///
+/// ```
+/// use smart_default::SmartDefault;
+///
+/// # fn main() {
+/// #[derive(SmartDefault)]
+/// # #[derive(PartialEq)]
+/// # #[allow(dead_code)]
+/// enum Foo {
+/// Bar,
+/// #[default]
+/// Baz {
+/// #[default = 12]
+/// a: i32,
+/// b: i32,
+/// #[default(Some(Default::default()))]
+/// c: Option<i32>,
+/// #[default(_code = "vec![1, 2, 3]")]
+/// d: Vec<u32>,
+/// #[default = "four"]
+/// e: String,
+/// },
+/// Qux(i32),
+/// }
+///
+/// assert!(Foo::default() == Foo::Baz {
+/// a: 12,
+/// b: 0,
+/// c: Some(0),
+/// d: vec![1, 2, 3],
+/// e: "four".to_owned(),
+/// });
+/// # }
+/// ```
+///
+/// * `Baz` has the `#[default]` attribute. This means that the default `Foo` is a `Foo::Baz`. Only
+/// one variant may have a `#[default]` attribute, and that attribute must have no value.
+/// * `a` has a `#[default = 12]` attribute. This means that it's default value is `12`.
+/// * `b` has no `#[default = ...]` attribute. It's default value will `i32`'s default value
+/// instead - `0`.
+/// * `c` is an `Option<i32>`, and it's default is `Some(Default::default())`. Rust cannot (currently)
+/// parse `#[default = Some(Default::default())]` and therefore we have to use a special syntax:
+/// `#[default(Some(Default::default))]`
+/// * `d` has the `!` token in it, which cannot (currently) be parsed even with `#[default(...)]`,
+/// so we have to encode it as a string and mark it as `_code = `.
+/// * `e` is a `String`, so the string literal "four" is automatically converted to it. This
+/// automatic conversion **only** happens to string (or byte string) literals - and only if
+/// `_code` is not used.
+/// * Documentation for the `impl Default` section is generated automatically, specifying the
+/// default value returned from `::default()`.
+#[proc_macro_derive(SmartDefault, attributes(default))]
+pub fn derive_smart_default(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+ let input = parse_macro_input!(input as DeriveInput);
+ match body_impl::impl_my_derive(&input) {
+ Ok(output) => output.into(),
+ Err(error) => error.to_compile_error().into(),
+ }
+}
diff --git a/third_party/rust/smart-default/src/util.rs b/third_party/rust/smart-default/src/util.rs
new file mode 100644
index 0000000000..0d4b247bbf
--- /dev/null
+++ b/third_party/rust/smart-default/src/util.rs
@@ -0,0 +1,21 @@
+use syn::parse::Error;
+use syn::spanned::Spanned;
+
+/// Return the value that fulfills the predicate if there is one in the slice. Panic if there is
+/// more than one.
+pub fn find_only<T, F>(iter: impl Iterator<Item = T>, pred: F) -> Result<Option<T>, Error>
+where
+ T: Spanned,
+ F: Fn(&T) -> Result<bool, Error>,
+{
+ let mut result = None;
+ for item in iter {
+ if pred(&item)? {
+ if result.is_some() {
+ return Err(Error::new(item.span(), "Multiple defaults"));
+ }
+ result = Some(item);
+ }
+ }
+ Ok(result)
+}
diff --git a/third_party/rust/smart-default/tests/tests.rs b/third_party/rust/smart-default/tests/tests.rs
new file mode 100644
index 0000000000..423c91df33
--- /dev/null
+++ b/third_party/rust/smart-default/tests/tests.rs
@@ -0,0 +1,170 @@
+use smart_default::SmartDefault;
+
+#[test]
+fn test_unit() {
+ #[derive(PartialEq, SmartDefault)]
+ struct Foo;
+
+ assert!(Foo::default() == Foo);
+}
+
+#[test]
+fn test_tuple() {
+ #[derive(PartialEq, SmartDefault)]
+ struct Foo(
+ #[default = 10] i32,
+ #[default = 20] i32,
+ // No default
+ i32,
+ );
+
+ assert!(Foo::default() == Foo(10, 20, 0));
+}
+
+#[test]
+fn test_struct() {
+ #[derive(PartialEq, SmartDefault)]
+ struct Foo {
+ #[default = 10]
+ x: i32,
+ #[default = 20]
+ y: i32,
+ // No default
+ z: i32,
+ }
+
+ assert!(Foo::default() == Foo { x: 10, y: 20, z: 0 });
+}
+
+#[test]
+fn test_enum_of_units() {
+ #[derive(PartialEq, SmartDefault)]
+ pub enum Foo {
+ #[allow(dead_code)]
+ Bar,
+ #[default]
+ Baz,
+ #[allow(dead_code)]
+ Qux,
+ }
+
+ assert!(Foo::default() == Foo::Baz);
+}
+
+#[test]
+fn test_enum_of_tuples() {
+ #[derive(PartialEq, SmartDefault)]
+ pub enum Foo {
+ #[allow(dead_code)]
+ Bar(i32),
+ #[default]
+ Baz(#[default = 10] i32, i32),
+ #[allow(dead_code)]
+ Qux(i32),
+ }
+
+ assert!(Foo::default() == Foo::Baz(10, 0));
+}
+
+#[test]
+fn test_enum_of_structs() {
+ #[derive(PartialEq, SmartDefault)]
+ pub enum Foo {
+ #[allow(dead_code)]
+ Bar { x: i32 },
+ #[default]
+ Baz {
+ #[default = 10]
+ y: i32,
+ z: i32,
+ },
+ #[allow(dead_code)]
+ Qux { w: i32 },
+ }
+
+ assert!(Foo::default() == Foo::Baz { y: 10, z: 0 });
+}
+
+#[test]
+fn test_enum_mixed() {
+ #[derive(PartialEq, SmartDefault)]
+ enum Foo {
+ #[allow(dead_code)]
+ Bar,
+ #[default]
+ Baz(#[default = 10] i32),
+ #[allow(dead_code)]
+ Qux { w: i32 },
+ }
+
+ assert!(Foo::default() == Foo::Baz(10));
+}
+
+#[test]
+fn test_generics_type_parameters() {
+ #[derive(PartialEq, SmartDefault)]
+ struct Foo<T>
+ where
+ T: Default,
+ {
+ #[default(Some(Default::default()))]
+ x: Option<T>,
+ }
+
+ assert!(Foo::default() == Foo { x: Some(0) });
+}
+
+#[test]
+fn test_generics_lifetime_parameters() {
+ // NOTE: A default value makes no sense with lifetime parameters, since ::default() receives no
+ // paramters and therefore can receive no lifetimes. But it does make sense if you make a variant
+ // without ref fields the default.
+
+ #[derive(PartialEq, SmartDefault)]
+ enum Foo<'a> {
+ #[default]
+ Bar(i32),
+ #[allow(dead_code)]
+ Baz(&'a str),
+ }
+
+ assert!(Foo::default() == Foo::Bar(0));
+}
+
+#[test]
+fn test_code_hack() {
+ #[derive(PartialEq, SmartDefault)]
+ struct Foo {
+ #[default(_code = "vec![1, 2, 3]")]
+ v: Vec<u32>,
+ }
+
+ assert!(Foo::default().v == [1, 2, 3]);
+}
+
+#[test]
+fn test_string_conversion() {
+ #[derive(PartialEq, SmartDefault)]
+ struct Foo(#[default = "one"] &'static str, #[default("two")] String);
+
+ assert!(Foo::default() == Foo("one", "two".to_owned()));
+}
+
+#[test]
+fn test_non_code_hack_valid_meta() {
+ #[derive(Debug, PartialEq, SmartDefault)]
+ struct Foo {
+ #[default(true)]
+ bar: bool,
+ #[default(Option::None)]
+ baz: Option<()>,
+ }
+
+ assert_eq!(
+ Foo::default(),
+ Foo {
+ bar: true,
+ baz: None
+ }
+ );
+}