// 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:
// .
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 = Discriminants::new(&data.variants).collect();
let captures: Vec> = 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(())
}
}
}