diff options
Diffstat (limited to '')
-rw-r--r-- | vendor/serde_repr/src/lib.rs | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/vendor/serde_repr/src/lib.rs b/vendor/serde_repr/src/lib.rs new file mode 100644 index 000000000..72e2c2bdd --- /dev/null +++ b/vendor/serde_repr/src/lib.rs @@ -0,0 +1,140 @@ +//! [![github]](https://github.com/dtolnay/serde-repr) [![crates-io]](https://crates.io/crates/serde_repr) [![docs-rs]](https://docs.rs/serde_repr) +//! +//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github +//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust +//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K +//! +//! <br> +//! +//! Derive `Serialize` and `Deserialize` that delegates to the underlying repr +//! of a C-like enum. +//! +//! # Examples +//! +//! ``` +//! use serde_repr::{Serialize_repr, Deserialize_repr}; +//! +//! #[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug)] +//! #[repr(u8)] +//! enum SmallPrime { +//! Two = 2, +//! Three = 3, +//! Five = 5, +//! Seven = 7, +//! } +//! +//! fn main() -> serde_json::Result<()> { +//! let j = serde_json::to_string(&SmallPrime::Seven)?; +//! assert_eq!(j, "7"); +//! +//! let p: SmallPrime = serde_json::from_str("2")?; +//! assert_eq!(p, SmallPrime::Two); +//! +//! Ok(()) +//! } +//! ``` + +#![allow(clippy::single_match_else)] + +extern crate proc_macro; + +mod parse; + +use proc_macro::TokenStream; +use quote::quote; +use syn::parse_macro_input; + +use crate::parse::Input; + +#[proc_macro_derive(Serialize_repr)] +pub fn derive_serialize(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as Input); + let ident = input.ident; + let repr = input.repr; + + let match_variants = input.variants.iter().map(|variant| { + let variant = &variant.ident; + quote! { + #ident::#variant => #ident::#variant as #repr, + } + }); + + TokenStream::from(quote! { + impl serde::Serialize for #ident { + #[allow(clippy::use_self)] + fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error> + where + S: serde::Serializer + { + let value: #repr = match *self { + #(#match_variants)* + }; + serde::Serialize::serialize(&value, serializer) + } + } + }) +} + +#[proc_macro_derive(Deserialize_repr, attributes(serde))] +pub fn derive_deserialize(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as Input); + let ident = input.ident; + let repr = input.repr; + let variants = input.variants.iter().map(|variant| &variant.ident); + + let declare_discriminants = input.variants.iter().map(|variant| { + let variant = &variant.ident; + quote! { + const #variant: #repr = #ident::#variant as #repr; + } + }); + + let match_discriminants = input.variants.iter().map(|variant| { + let variant = &variant.ident; + quote! { + discriminant::#variant => core::result::Result::Ok(#ident::#variant), + } + }); + + let error_format = match input.variants.len() { + 1 => "invalid value: {}, expected {}".to_owned(), + 2 => "invalid value: {}, expected {} or {}".to_owned(), + n => "invalid value: {}, expected one of: {}".to_owned() + &", {}".repeat(n - 1), + }; + + let other_arm = match input.default_variant { + Some(variant) => { + let variant = &variant.ident; + quote! { + core::result::Result::Ok(#ident::#variant) + } + } + None => quote! { + core::result::Result::Err(serde::de::Error::custom( + format_args!(#error_format, other #(, discriminant::#variants)*) + )) + }, + }; + + TokenStream::from(quote! { + impl<'de> serde::Deserialize<'de> for #ident { + #[allow(clippy::use_self)] + fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error> + where + D: serde::Deserializer<'de>, + { + struct discriminant; + + #[allow(non_upper_case_globals)] + impl discriminant { + #(#declare_discriminants)* + } + + match <#repr as serde::Deserialize>::deserialize(deserializer)? { + #(#match_discriminants)* + other => #other_arm, + } + } + } + }) +} |