diff --git a/buffa-codegen/src/impl_message.rs b/buffa-codegen/src/impl_message.rs index 31d710c..229ca38 100644 --- a/buffa-codegen/src/impl_message.rs +++ b/buffa-codegen/src/impl_message.rs @@ -914,7 +914,11 @@ fn type_encoded_size_expr(ty: Type, val: &TokenStream) -> TokenStream { quote! { ::buffa::types::FIXED64_ENCODED_LEN as u32 } } Type::TYPE_BOOL => quote! { ::buffa::types::BOOL_ENCODED_LEN as u32 }, - _ => unreachable!( + Type::TYPE_STRING + | Type::TYPE_BYTES + | Type::TYPE_ENUM + | Type::TYPE_MESSAGE + | Type::TYPE_GROUP => unreachable!( "type_encoded_size_expr called for non-numeric type {:?}", ty ), @@ -1016,7 +1020,11 @@ fn encode_fn_token(ty: Type) -> TokenStream { Type::TYPE_FLOAT => quote! { ::buffa::types::encode_float }, Type::TYPE_DOUBLE => quote! { ::buffa::types::encode_double }, Type::TYPE_BOOL => quote! { ::buffa::types::encode_bool }, - _ => unreachable!("encode_fn_token called for non-numeric type {:?}", ty), + Type::TYPE_STRING + | Type::TYPE_BYTES + | Type::TYPE_ENUM + | Type::TYPE_MESSAGE + | Type::TYPE_GROUP => unreachable!("encode_fn_token called for non-numeric type {:?}", ty), } } @@ -1035,7 +1043,11 @@ pub(crate) fn decode_fn_token(ty: Type) -> TokenStream { Type::TYPE_FLOAT => quote! { ::buffa::types::decode_float }, Type::TYPE_DOUBLE => quote! { ::buffa::types::decode_double }, Type::TYPE_BOOL => quote! { ::buffa::types::decode_bool }, - _ => unreachable!("decode_fn_token called for non-numeric type {:?}", ty), + Type::TYPE_STRING + | Type::TYPE_BYTES + | Type::TYPE_ENUM + | Type::TYPE_MESSAGE + | Type::TYPE_GROUP => unreachable!("decode_fn_token called for non-numeric type {:?}", ty), } } @@ -1056,7 +1068,13 @@ pub(crate) fn is_non_default_expr(ty: Type, field_ident: &Ident) -> TokenStream Type::TYPE_FLOAT => quote! { self.#field_ident.to_bits() != 0u32 }, Type::TYPE_DOUBLE => quote! { self.#field_ident.to_bits() != 0u64 }, Type::TYPE_BOOL => quote! { self.#field_ident }, - _ => unreachable!("is_non_default_expr called for non-numeric type {:?}", ty), + Type::TYPE_STRING + | Type::TYPE_BYTES + | Type::TYPE_ENUM + | Type::TYPE_MESSAGE + | Type::TYPE_GROUP => { + unreachable!("is_non_default_expr called for non-numeric type {:?}", ty) + } } } @@ -1959,7 +1977,28 @@ fn repeated_merge_arm( quote! { ::buffa::types::decode_bytes(buf)? } } } - _ => unreachable!("repeated_merge_arm: unhandled unpacked type {:?}", ty), + // Message and group are handled by early returns above; the + // remaining types satisfy `is_packed_type` and never reach this + // unpacked branch. Enumerated so adding a `Type` variant is a + // compile error here rather than a runtime panic during codegen. + Type::TYPE_MESSAGE + | Type::TYPE_GROUP + | Type::TYPE_ENUM + | Type::TYPE_BOOL + | Type::TYPE_INT32 + | Type::TYPE_INT64 + | Type::TYPE_UINT32 + | Type::TYPE_UINT64 + | Type::TYPE_SINT32 + | Type::TYPE_SINT64 + | Type::TYPE_FIXED32 + | Type::TYPE_FIXED64 + | Type::TYPE_SFIXED32 + | Type::TYPE_SFIXED64 + | Type::TYPE_FLOAT + | Type::TYPE_DOUBLE => { + unreachable!("repeated_merge_arm: unhandled unpacked type {:?}", ty) + } }; return Ok(quote! { #field_number => { diff --git a/buffa-codegen/src/impl_text.rs b/buffa-codegen/src/impl_text.rs index 05a1ea3..082d786 100644 --- a/buffa-codegen/src/impl_text.rs +++ b/buffa-codegen/src/impl_text.rs @@ -713,7 +713,17 @@ fn repeated_merge_arm( Type::TYPE_FLOAT => quote! { __d.read_f32() }, Type::TYPE_DOUBLE => quote! { __d.read_f64() }, Type::TYPE_BOOL => quote! { __d.read_bool() }, - _ => unreachable!(), + // The outer match handles all non-numeric variants in its + // earlier arms, so only numeric scalars reach this `_` branch. + // Listed here so the inner match stays exhaustive — adding a + // `Type` variant becomes a compile error rather than a panic. + Type::TYPE_STRING + | Type::TYPE_BYTES + | Type::TYPE_ENUM + | Type::TYPE_MESSAGE + | Type::TYPE_GROUP => { + unreachable!("text repeated read arm: non-numeric type {:?}", ty) + } }; quote! { #call } } diff --git a/buffa-codegen/src/oneof.rs b/buffa-codegen/src/oneof.rs index d40c1b5..7cc89e7 100644 --- a/buffa-codegen/src/oneof.rs +++ b/buffa-codegen/src/oneof.rs @@ -588,7 +588,9 @@ pub(crate) fn to_snake_case(s: &str) -> String { result.push('_'); } } - result.push(c.to_lowercase().next().unwrap()); + // `to_lowercase()` may yield multiple chars (e.g. `İ` → `i\u{307}`); + // extend with the full sequence rather than truncating to the first. + result.extend(c.to_lowercase()); } result } diff --git a/buffa-codegen/src/view.rs b/buffa-codegen/src/view.rs index 6989567..fae95ce 100644 --- a/buffa-codegen/src/view.rs +++ b/buffa-codegen/src/view.rs @@ -1018,7 +1018,28 @@ fn repeated_decode_arm( let borrow = match ty { Type::TYPE_STRING => quote! { ::buffa::types::borrow_str(&mut cur)? }, Type::TYPE_BYTES => quote! { ::buffa::types::borrow_bytes(&mut cur)? }, - _ => unreachable!(), + // Message and group are handled by early returns above; the + // remaining types satisfy `is_packed_type` and never reach this + // unpacked branch. Enumerated so adding a `Type` variant is a + // compile error here rather than a runtime panic during codegen. + Type::TYPE_MESSAGE + | Type::TYPE_GROUP + | Type::TYPE_ENUM + | Type::TYPE_BOOL + | Type::TYPE_INT32 + | Type::TYPE_INT64 + | Type::TYPE_UINT32 + | Type::TYPE_UINT64 + | Type::TYPE_SINT32 + | Type::TYPE_SINT64 + | Type::TYPE_FIXED32 + | Type::TYPE_FIXED64 + | Type::TYPE_SFIXED32 + | Type::TYPE_SFIXED64 + | Type::TYPE_FLOAT + | Type::TYPE_DOUBLE => { + unreachable!("view repeated decode arm: unhandled unpacked type {:?}", ty) + } }; return Ok(quote! { #field_number => { @@ -2023,7 +2044,13 @@ fn scalar_skip_predicate(ty: Type) -> TokenStream { // The single call site is gated by `serde_helper_path(ty).is_some()`, // which only matches the scalar types above. Bytes is handled in an // earlier match arm. - _ => unreachable!("scalar_skip_predicate called for non-scalar"), + Type::TYPE_STRING + | Type::TYPE_BYTES + | Type::TYPE_ENUM + | Type::TYPE_MESSAGE + | Type::TYPE_GROUP => { + unreachable!("scalar_skip_predicate called for non-scalar {:?}", ty) + } } } @@ -2135,7 +2162,11 @@ fn scalar_ty(ty: Type) -> TokenStream { Type::TYPE_INT32 | Type::TYPE_SINT32 | Type::TYPE_SFIXED32 => quote! { i32 }, Type::TYPE_UINT32 | Type::TYPE_FIXED32 => quote! { u32 }, Type::TYPE_BOOL => quote! { bool }, - _ => unreachable!("scalar_ty called for non-scalar {:?}", ty), + Type::TYPE_STRING + | Type::TYPE_BYTES + | Type::TYPE_ENUM + | Type::TYPE_MESSAGE + | Type::TYPE_GROUP => unreachable!("scalar_ty called for non-scalar {:?}", ty), } } diff --git a/protoc-gen-buffa/src/main.rs b/protoc-gen-buffa/src/main.rs index e01922e..692d994 100644 --- a/protoc-gen-buffa/src/main.rs +++ b/protoc-gen-buffa/src/main.rs @@ -110,12 +110,13 @@ fn run() -> Result<(), Box> { &config.codegen, )?; - // Build the response. + // Build the response. `generated` is consumed here so the names and + // contents move directly into the response rather than being cloned. let files: Vec = generated - .iter() + .into_iter() .map(|g| CodeGeneratorResponseFile { - name: Some(g.name.clone()), - content: Some(g.content.clone()), + name: Some(g.name), + content: Some(g.content), ..Default::default() }) .collect();