oct/oct-macros/src/impls/encode_enum.rs
Gabriel Bjørnager Jensen 12975eabf5 Reimplement 'Decode' for 'alloc::vec::Vec', 'alloc::string::String', 'CString', 'LinkedList', 'HashMap', and 'HashSet'; Reimplement 'DecodeBorrowed' for 'alloc::vec::Vec', 'alloc::string::String', and 'CString'; Update and add tests; Update readme; Clean up code; Implement 'From<Infallible>' for all error types; Update docs; Rework 'EnumEncodeError' and 'EnumDecodeError'; Add 'encode_char' benchmark; Implement 'Encode' and 'Decode' for 'OsStr', 'OsString', 'c_void', and 'BinaryHeap'; Remove 'never-type' feature flag; Rework 'PrimDiscriminant' as 'PrimRepr'; Add 'PrimDiscriminant' enumeration; Implement 'From<T: PrimRepr>' for 'PrimDiscriminant'; Implement 'PrimRepr' for 'u8', 'u16', 'u32', 'u64', 'u128', 'usize', 'i8', 'i16', 'i32', 'i64', 'i128', and 'isize'; Implement 'Debug', 'Display', 'Binary', 'Octal', 'LowerHex', 'UpperHex', 'LowerExp', and 'UpperExp' for 'PrimDiscriminant'; Implement 'Clone', 'Copy', 'Eq', 'PartialEq', and 'Hash' for 'PrimDiscriminant'; Implement 'Eq' and 'PartialEq' for **all** error types; Add 'as_slice' and 'as_ptr' methods to 'Input'; Implement 'AsRef<[u8]>' and 'Borrow<[u8]>' for 'Input'; Implement 'SizedEncode' for 'c_void'; Fix '<LinkedList as Encode>::Error'; Add 'new_unchecked' constructor to 'String' and 'Vec'; Rework 'from_utf8' and 'from_utf8_unchecked' in 'String'; Remove 'StringError'; Rework 'String' to make it trivially-destructable; Actually mark 'String::as_mut_str' with 'const'; Unimplement 'PartialOrd<{&str, alloc::string::String}>' for 'String'; Implement 'PartialEq<str>' for 'String'; Unimplement 'PartialOrd<{[T; M], &[T], alloc::vec::Vec<T>}>' for 'Vec<T, N>'; Remove 'is_full' method from 'String' and 'Vec'; Implement 'Copy' for 'String'; Implement 'PartialEq<{Self, [u8], &[u8]}>', 'Eq', and 'Debug' for 'Input'; Implement 'PartialEq<[U]>' for 'Vec<T, ..>'; Implement 'PartialEq<Vec<U, ..>>' for 'alloc::vec::Vec<T>'; Implement 'PartialEq<String>' for 'alloc::string::String'; Add 'is_char_boundary' and 'as_mut_bytes' methods to 'String'; Add doc aliases; Update lints; Fix atomics being imported from 'std';
2025-01-14 21:58:12 +01:00

81 lines
2.1 KiB
Rust

// Copyright 2024-2025 Gabriel Bjørnager Jensen.
//
// This Source Code Form is subject to the terms of
// the Mozilla Public License, v. 2.0. If a copy of
// the MPL was not distributed with this file, you
// can obtain one at:
// <https://mozilla.org/MPL/2.0/>.
use crate::{Discriminants, Repr};
use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::{DataEnum, Fields, Ident, LitInt};
#[must_use]
pub fn encode_enum(data: DataEnum, repr: Repr) -> TokenStream {
let discriminants: Vec<LitInt> = Discriminants::new(&data.variants).collect();
let captures: Vec<Vec<Ident>> = data
.variants
.iter()
.map(|variant| {
variant
.fields
.iter()
.enumerate()
.map(|(index, _)| Ident::new(&format!("value{index}"), Span::call_site()))
.collect()
})
.collect();
let patterns = data
.variants
.into_iter()
.zip(&captures)
.map(|(variant, captures)| {
let variant_name = variant.ident;
match variant.fields {
Fields::Unit => quote! { Self::#variant_name },
Fields::Unnamed(_fields) => quote! { Self::#variant_name (#(ref #captures, )*) },
Fields::Named(fields) => {
let field_names = fields
.named
.into_iter()
.map(|field| field.ident.unwrap());
quote! { Self::#variant_name { #(#field_names: ref #captures, )* } }
},
}
});
quote! {
type Error = ::oct::error::EnumEncodeError<<#repr as ::oct::encode::Encode>::Error, ::oct::error::GenericEncodeError>;
#[allow(unreachable_patterns)]
#[inline]
fn encode(&self, stream: &mut ::oct::encode::Output) -> ::core::result::Result<(), Self::Error> {
match *self {
#(
#patterns => {
<#repr as ::oct::encode::Encode>::encode(&#discriminants, stream)
.map_err(::oct::error::EnumEncodeError::BadDiscriminant)?;
#(
::oct::encode::Encode::encode(#captures, stream)
.map_err(::core::convert::Into::<::oct::error::GenericEncodeError>::into)
.map_err(::oct::error::EnumEncodeError::BadField)?;
)*
}
)*
_ => ::core::unreachable!("no variants defined for this enumeration"),
}
::core::result::Result::Ok(())
}
}
}