diff --git a/conjure-codegen/src/aliases.rs b/conjure-codegen/src/aliases.rs index c1c75040..550a8998 100644 --- a/conjure-codegen/src/aliases.rs +++ b/conjure-codegen/src/aliases.rs @@ -37,15 +37,9 @@ pub fn generate(ctx: &Context, def: &AliasDefinition) -> TokenStream { } if ctx.is_double(def.alias()) { - derives.push("conjure_object::private::Educe"); - type_attrs.push(quote!(#[educe(PartialEq, Eq, PartialOrd, Ord, Hash)])); - field_attrs.push(quote! { - #[educe( - PartialEq(method(conjure_object::private::DoubleOps::eq)), - Ord(method(conjure_object::private::DoubleOps::cmp)), - Hash(method(conjure_object::private::DoubleOps::hash)), - )] - }) + derives.push("conjure_object::private::DeriveWith"); + type_attrs.push(quote!(#[derive_with(PartialEq, Eq, PartialOrd, Ord, Hash)])); + field_attrs.push(quote!(#[derive_with(with = conjure_object::private::DoubleWrapper)])); } else { derives.push("PartialEq"); derives.push("Eq"); @@ -59,7 +53,7 @@ pub fn generate(ctx: &Context, def: &AliasDefinition) -> TokenStream { } let derives = derives.iter().map(|s| s.parse::().unwrap()); - // The derive attr has to be before the educe attr, so insert rather than push + // The derive attr has to be before the derive_with attr, so insert rather than push type_attrs.insert(0, quote!(#[derive(#(#derives),*)])); let display = if ctx.is_display(def.alias()) { diff --git a/conjure-codegen/src/example_types/objects/product/alias_as_map_key_example.rs b/conjure-codegen/src/example_types/objects/product/alias_as_map_key_example.rs index ac147103..9b538445 100644 --- a/conjure-codegen/src/example_types/objects/product/alias_as_map_key_example.rs +++ b/conjure-codegen/src/example_types/objects/product/alias_as_map_key_example.rs @@ -3,10 +3,10 @@ Clone, conjure_object::serde::Serialize, conjure_object::serde::Deserialize, - conjure_object::private::Educe + conjure_object::private::DeriveWith )] #[serde(crate = "conjure_object::serde")] -#[educe(PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive_with(PartialEq, Eq, PartialOrd, Ord, Hash)] #[conjure_object::private::staged_builder::staged_builder] #[builder(crate = conjure_object::private::staged_builder, update, inline)] pub struct AliasAsMapKeyExample { diff --git a/conjure-codegen/src/example_types/objects/product/double_alias_example.rs b/conjure-codegen/src/example_types/objects/product/double_alias_example.rs index 6d5d9a9e..022a4829 100644 --- a/conjure-codegen/src/example_types/objects/product/double_alias_example.rs +++ b/conjure-codegen/src/example_types/objects/product/double_alias_example.rs @@ -4,17 +4,13 @@ conjure_object::serde::Deserialize, conjure_object::serde::Serialize, Copy, - conjure_object::private::Educe, + conjure_object::private::DeriveWith, Default )] #[serde(crate = "conjure_object::serde", transparent)] -#[educe(PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive_with(PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct DoubleAliasExample( - #[educe( - PartialEq(method(conjure_object::private::DoubleOps::eq)), - Ord(method(conjure_object::private::DoubleOps::cmp)), - Hash(method(conjure_object::private::DoubleOps::hash)), - )] + #[derive_with(with = conjure_object::private::DoubleWrapper)] pub f64, ); impl std::fmt::Display for DoubleAliasExample { diff --git a/conjure-codegen/src/example_types/objects/product/double_example.rs b/conjure-codegen/src/example_types/objects/product/double_example.rs index 540b2ed0..7a60c589 100644 --- a/conjure-codegen/src/example_types/objects/product/double_example.rs +++ b/conjure-codegen/src/example_types/objects/product/double_example.rs @@ -3,20 +3,16 @@ Clone, conjure_object::serde::Serialize, conjure_object::serde::Deserialize, - conjure_object::private::Educe, + conjure_object::private::DeriveWith, Copy )] #[serde(crate = "conjure_object::serde")] -#[educe(PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive_with(PartialEq, Eq, PartialOrd, Ord, Hash)] #[conjure_object::private::staged_builder::staged_builder] #[builder(crate = conjure_object::private::staged_builder, update, inline)] pub struct DoubleExample { #[serde(rename = "doubleValue")] - #[educe( - PartialEq(method(conjure_object::private::DoubleOps::eq)), - Ord(method(conjure_object::private::DoubleOps::cmp)), - Hash(method(conjure_object::private::DoubleOps::hash)), - )] + #[derive_with(with = conjure_object::private::DoubleWrapper)] double_value: f64, } impl DoubleExample { diff --git a/conjure-codegen/src/example_types/objects/product/list_example.rs b/conjure-codegen/src/example_types/objects/product/list_example.rs index 5bd451a5..569ceb4b 100644 --- a/conjure-codegen/src/example_types/objects/product/list_example.rs +++ b/conjure-codegen/src/example_types/objects/product/list_example.rs @@ -3,10 +3,10 @@ Clone, conjure_object::serde::Serialize, conjure_object::serde::Deserialize, - conjure_object::private::Educe + conjure_object::private::DeriveWith )] #[serde(crate = "conjure_object::serde")] -#[educe(PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive_with(PartialEq, Eq, PartialOrd, Ord, Hash)] #[conjure_object::private::staged_builder::staged_builder] #[builder(crate = conjure_object::private::staged_builder, update, inline)] pub struct ListExample { @@ -18,11 +18,7 @@ pub struct ListExample { primitive_items: Vec, #[builder(default, list(item(type = f64)))] #[serde(rename = "doubleItems", skip_serializing_if = "Vec::is_empty", default)] - #[educe( - PartialEq(method(conjure_object::private::DoubleOps::eq)), - Ord(method(conjure_object::private::DoubleOps::cmp)), - Hash(method(conjure_object::private::DoubleOps::hash)), - )] + #[derive_with(with = conjure_object::private::DoubleWrapper)] double_items: Vec, } impl ListExample { diff --git a/conjure-codegen/src/example_types/objects/product/many_field_example.rs b/conjure-codegen/src/example_types/objects/product/many_field_example.rs index 2f65a007..073efcdf 100644 --- a/conjure-codegen/src/example_types/objects/product/many_field_example.rs +++ b/conjure-codegen/src/example_types/objects/product/many_field_example.rs @@ -3,10 +3,10 @@ Clone, conjure_object::serde::Serialize, conjure_object::serde::Deserialize, - conjure_object::private::Educe + conjure_object::private::DeriveWith )] #[serde(crate = "conjure_object::serde")] -#[educe(PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive_with(PartialEq, Eq, PartialOrd, Ord, Hash)] #[conjure_object::private::staged_builder::staged_builder] #[builder(crate = conjure_object::private::staged_builder, update, inline)] pub struct ManyFieldExample { @@ -16,11 +16,7 @@ pub struct ManyFieldExample { #[serde(rename = "integer")] integer: i32, #[serde(rename = "doubleValue")] - #[educe( - PartialEq(method(conjure_object::private::DoubleOps::eq)), - Ord(method(conjure_object::private::DoubleOps::cmp)), - Hash(method(conjure_object::private::DoubleOps::hash)), - )] + #[derive_with(with = conjure_object::private::DoubleWrapper)] double_value: f64, #[builder(default, into)] #[serde(rename = "optionalItem", skip_serializing_if = "Option::is_none", default)] diff --git a/conjure-codegen/src/example_types/objects/product/primitive_optionals_example.rs b/conjure-codegen/src/example_types/objects/product/primitive_optionals_example.rs index cb1dc28a..1ddd01f0 100644 --- a/conjure-codegen/src/example_types/objects/product/primitive_optionals_example.rs +++ b/conjure-codegen/src/example_types/objects/product/primitive_optionals_example.rs @@ -3,20 +3,16 @@ Clone, conjure_object::serde::Serialize, conjure_object::serde::Deserialize, - conjure_object::private::Educe + conjure_object::private::DeriveWith )] #[serde(crate = "conjure_object::serde")] -#[educe(PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive_with(PartialEq, Eq, PartialOrd, Ord, Hash)] #[conjure_object::private::staged_builder::staged_builder] #[builder(crate = conjure_object::private::staged_builder, update, inline)] pub struct PrimitiveOptionalsExample { #[builder(default, into)] #[serde(rename = "num", skip_serializing_if = "Option::is_none", default)] - #[educe( - PartialEq(method(conjure_object::private::DoubleOps::eq)), - Ord(method(conjure_object::private::DoubleOps::cmp)), - Hash(method(conjure_object::private::DoubleOps::hash)), - )] + #[derive_with(with = conjure_object::private::DoubleWrapper)] num: Option, #[builder(default, into)] #[serde(rename = "bool", skip_serializing_if = "Option::is_none", default)] diff --git a/conjure-codegen/src/objects.rs b/conjure-codegen/src/objects.rs index 93d813bc..37554514 100644 --- a/conjure-codegen/src/objects.rs +++ b/conjure-codegen/src/objects.rs @@ -29,8 +29,8 @@ pub fn generate(ctx: &Context, base_module: BaseModule, def: &ObjectDefinition) ]; if def.fields().iter().any(|v| ctx.has_double(v.type_())) { - derives.push("conjure_object::private::Educe"); - type_attrs.push(quote!(#[educe(PartialEq, Eq, PartialOrd, Ord, Hash)])); + derives.push("conjure_object::private::DeriveWith"); + type_attrs.push(quote!(#[derive_with(PartialEq, Eq, PartialOrd, Ord, Hash)])); } else { derives.push("PartialEq"); derives.push("Eq"); @@ -44,7 +44,7 @@ pub fn generate(ctx: &Context, base_module: BaseModule, def: &ObjectDefinition) } let derives = derives.iter().map(|s| s.parse::().unwrap()); - // The derive attr has to be before the educe attr, so insert rather than push + // The derive attr has to be before the derive_with attr, so insert rather than push type_attrs.insert(0, quote!(#[derive(#(#derives),*)])); let field_attrs = def.fields().iter().map(|s| { @@ -52,11 +52,7 @@ pub fn generate(ctx: &Context, base_module: BaseModule, def: &ObjectDefinition) let serde_attr = serde_field_attr(ctx, def, s); let educe_attr = if ctx.is_double(s.type_()) { quote! { - #[educe( - PartialEq(method(conjure_object::private::DoubleOps::eq)), - Ord(method(conjure_object::private::DoubleOps::cmp)), - Hash(method(conjure_object::private::DoubleOps::hash)), - )] + #[derive_with(with = conjure_object::private::DoubleWrapper)] } } else { quote!() diff --git a/conjure-codegen/src/unions.rs b/conjure-codegen/src/unions.rs index 3a2d5c4a..e9a43615 100644 --- a/conjure-codegen/src/unions.rs +++ b/conjure-codegen/src/unions.rs @@ -60,8 +60,8 @@ fn generate_enum(ctx: &Context, def: &UnionDefinition) -> TokenStream { let mut type_attrs = vec![]; let mut derives = vec!["Debug", "Clone"]; if def.union_().iter().any(|v| ctx.has_double(v.type_())) { - derives.push("conjure_object::private::Educe"); - type_attrs.push(quote!(#[educe(PartialEq, Eq, PartialOrd, Ord, Hash)])); + derives.push("conjure_object::private::DeriveWith"); + type_attrs.push(quote!(#[derive_with(PartialEq, Eq, PartialOrd, Ord, Hash)])); } else { derives.push("PartialEq"); derives.push("Eq"); @@ -70,7 +70,7 @@ fn generate_enum(ctx: &Context, def: &UnionDefinition) -> TokenStream { derives.push("Hash"); } let derives = derives.iter().map(|s| s.parse::().unwrap()); - // The derive attr has to be before the educe attr, so insert rather than push + // The derive attr has to be before the derive_with attr, so insert rather than push type_attrs.insert(0, quote!(#[derive(#(#derives),*)])); let docs = def.union_().iter().map(|f| ctx.docs(f.docs())); @@ -84,11 +84,7 @@ fn generate_enum(ctx: &Context, def: &UnionDefinition) -> TokenStream { .map(|f| { let attr = if ctx.is_double(f.type_()) { quote! { - #[educe( - PartialEq(method(conjure_object::private::DoubleOps::eq)), - Ord(method(conjure_object::private::DoubleOps::cmp)), - Hash(method(conjure_object::private::DoubleOps::hash)), - )] + #[derive_with(with = conjure_object::private::DoubleWrapper)] } } else { quote!() diff --git a/conjure-http/src/private/client/mod.rs b/conjure-http/src/private/client/mod.rs index 77556096..5d14b953 100644 --- a/conjure-http/src/private/client/mod.rs +++ b/conjure-http/src/private/client/mod.rs @@ -42,14 +42,14 @@ where Request::new(AsyncRequestBody::Empty) } -pub fn encode_serializable_request(body: &T) -> Request> +pub fn encode_serializable_request(body: &'_ T) -> Request> where T: Serialize, { inner_encode_serializable_request(body, RequestBody::Fixed) } -pub fn async_encode_serializable_request(body: &T) -> Request> +pub fn async_encode_serializable_request(body: &'_ T) -> Request> where T: Serialize, { diff --git a/conjure-macros/src/derive_with.rs b/conjure-macros/src/derive_with.rs new file mode 100644 index 00000000..6370d0b4 --- /dev/null +++ b/conjure-macros/src/derive_with.rs @@ -0,0 +1,341 @@ +// Copyright 2025 Palantir Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use proc_macro2::{Span, TokenStream}; +use quote::quote; +use structmeta::StructMeta; +use syn::{parse_macro_input, Data, DeriveInput, Expr, Field, Fields, Ident, Variant}; + +#[derive(StructMeta)] +struct ItemAttr { + #[struct_meta(name = "PartialEq")] + partial_eq: bool, + #[struct_meta(name = "Eq")] + eq: bool, + #[struct_meta(name = "PartialOrd")] + partial_ord: bool, + #[struct_meta(name = "Ord")] + ord: bool, + #[struct_meta(name = "Hash")] + hash: bool, +} + +#[derive(StructMeta)] +struct FieldAttr { + with: Expr, +} + +pub fn generate(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let input = parse_macro_input!(input as DeriveInput); + + let delegate = Ident::new(&format!("__{}Delegate", input.ident), input.ident.span()); + let delegate_item = generate_delegate(&input, &delegate); + let from_impl = generate_from_impl(&input, &delegate); + + let mut derives = vec![]; + let mut impls = vec![]; + + for attr in &input.attrs { + if attr.path().is_ident("derive_with") { + let attr = match attr.parse_args::() { + Ok(attr) => attr, + Err(e) => return e.into_compile_error().into(), + }; + + if attr.partial_eq { + derives.push(quote!(PartialEq)); + impls.push(generate_partial_eq(&input, &delegate)); + } + + if attr.eq { + derives.push(quote!(Eq)); + impls.push(generate_eq(&input)); + } + + if attr.partial_ord { + derives.push(quote!(PartialOrd)); + impls.push(generate_partial_ord(&input)); + } + + if attr.ord { + derives.push(quote!(Ord)); + impls.push(generate_ord(&input, &delegate)); + } + + if attr.hash { + derives.push(quote!(Hash)); + impls.push(generate_hash(&input, &delegate)); + } + } + } + + quote! { + const _: () = { + #[derive(#(#derives),*)] + #delegate_item + + #from_impl + + #(#impls)* + }; + } + .into() +} + +fn generate_delegate(input: &DeriveInput, ident: &Ident) -> TokenStream { + let lt = quote!('__a); + + match &input.data { + Data::Struct(data_struct) => match &data_struct.fields { + Fields::Named(fields_named) => { + let idents = fields_named.named.iter().map(|f| &f.ident); + let tys = fields_named.named.iter().map(|f| generate_field_ty(f, <)); + + quote! { + struct #ident<#lt> { + #(#idents: #tys),* + } + } + } + Fields::Unnamed(fields_unnamed) => { + let tys = fields_unnamed + .unnamed + .iter() + .map(|f| generate_field_ty(f, <)); + + quote! { + struct #ident<#lt>(#(#tys),*); + } + } + Fields::Unit => quote! { + struct #ident; + }, + }, + Data::Enum(data_enum) => { + let variants = data_enum.variants.iter().map(|v| generate_variant(v, <)); + + quote! { + enum #ident<#lt> { + #(#variants),* + } + } + } + Data::Union(_) => quote!(compile_error!("DeriveWith does not support unions")), + } +} + +fn extract_with(field: &Field) -> Option { + for attr in &field.attrs { + if attr.path().is_ident("derive_with") { + let attr = match attr.parse_args::() { + Ok(attr) => attr, + Err(e) => return Some(e.into_compile_error()), + }; + + let with = attr.with; + return Some(quote!(#with)); + } + } + + None +} + +fn generate_field_ty(field: &Field, lt: &TokenStream) -> TokenStream { + let ty = &field.ty; + let mut ty = quote!(&#lt #ty); + if let Some(with) = extract_with(field) { + ty = quote!(#with<#ty>); + } + + ty +} + +fn generate_variant(variant: &Variant, lt: &TokenStream) -> TokenStream { + let ident = &variant.ident; + let discriminant = &variant.discriminant.as_ref().map(|(eq, e)| quote!(#eq #e)); + + match &variant.fields { + Fields::Named(fields_named) => { + let field_idents = fields_named.named.iter().map(|f| &f.ident); + let field_tys = fields_named.named.iter().map(|f| generate_field_ty(f, lt)); + quote!(#ident { #(#field_idents: #field_tys),* } #discriminant) + } + Fields::Unnamed(fields_unnamed) => { + let field_tys = fields_unnamed + .unnamed + .iter() + .map(|f| generate_field_ty(f, lt)); + quote!(#ident(#(#field_tys),*) #discriminant) + } + Fields::Unit => quote!(#ident #discriminant), + } +} + +fn generate_from_impl(input: &DeriveInput, delegate: &Ident) -> TokenStream { + let lt = quote!('__a); + let ident = &input.ident; + + let constructor = match &input.data { + Data::Struct(data_struct) => { + let fields = data_struct + .fields + .members() + .zip(data_struct.fields.iter().map(extract_with)) + .map(|(member, with)| { + let mut expr = quote!(&v.#member); + if let Some(with) = with { + expr = quote!(#with(#expr)); + } + + quote!(#member: #expr) + }); + + quote! { + #delegate { + #(#fields),* + } + } + } + Data::Enum(data_enum) => { + let variants = data_enum + .variants + .iter() + .map(|variant| generate_variant_arm(&input.ident, variant)); + + quote! { + match v { + #(#variants),* + } + } + } + Data::Union(_) => quote!(compile_error!("DeriveWith does not support unions")), + }; + + quote! { + impl<#lt> std::convert::From<&#lt #ident> for #delegate<#lt> { + #[inline] + #[allow(deprecated)] + fn from(v: &#lt #ident) -> Self { + #constructor + } + } + } +} + +fn generate_variant_arm(ident: &Ident, variant: &Variant) -> TokenStream { + let variant_ident = &variant.ident; + match &variant.fields { + Fields::Named(fields_named) => { + let names = fields_named.named.iter().map(|f| &f.ident); + let constructor = fields_named.named.iter().map(|f| { + let name = &f.ident; + let mut expr = quote!(#name); + if let Some(with) = extract_with(f) { + expr = quote!(#with(#expr)); + } + expr + }); + + quote! { + #ident::#variant_ident { #(#names),* } => Self::#variant_ident { #(#constructor),* } + } + } + Fields::Unnamed(fields_unnamed) => { + let names = fields_unnamed + .unnamed + .iter() + .enumerate() + .map(|(i, _)| Ident::new(&format!("__f{i}"), Span::call_site())); + let constructor = fields_unnamed.unnamed.iter().enumerate().map(|(i, f)| { + let name = Ident::new(&format!("__f{i}"), Span::call_site()); + let mut expr = quote!(#name); + if let Some(with) = extract_with(f) { + expr = quote!(#with(#expr)); + } + expr + }); + + quote! { + #ident::#variant_ident(#(#names),*) => Self::#variant_ident(#(#constructor),*) + } + } + Fields::Unit => quote!(#ident::#variant_ident => Self::#variant_ident), + } +} + +fn generate_partial_eq(input: &DeriveInput, delegate: &Ident) -> TokenStream { + let ident = &input.ident; + + quote! { + impl std::cmp::PartialEq for #ident { + #[inline] + fn eq(&self, other: &Self) -> bool { + std::cmp::PartialEq::eq( + &<#delegate as std::convert::From<_>>::from(self), + &<#delegate as std::convert::From<_>>::from(other), + ) + } + } + } +} + +fn generate_eq(input: &DeriveInput) -> TokenStream { + let ident = &input.ident; + + quote! { + impl std::cmp::Eq for #ident {} + } +} + +fn generate_partial_ord(input: &DeriveInput) -> TokenStream { + let ident = &input.ident; + + quote! { + impl std::cmp::PartialOrd for #ident { + #[inline] + fn partial_cmp(&self, other: &Self) -> std::option::Option { + std::option::Option::Some(std::cmp::Ord::cmp(self, other)) + } + } + } +} + +fn generate_ord(input: &DeriveInput, delegate: &Ident) -> TokenStream { + let ident = &input.ident; + + quote! { + impl std::cmp::Ord for #ident { + #[inline] + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + std::cmp::Ord::cmp( + &<#delegate as std::convert::From<_>>::from(self), + &<#delegate as std::convert::From<_>>::from(other), + ) + } + } + } +} + +fn generate_hash(input: &DeriveInput, delegate: &Ident) -> TokenStream { + let ident = &input.ident; + + quote! { + impl std::hash::Hash for #ident { + #[inline] + fn hash(&self, hasher: &mut H) { + std::hash::Hash::hash(&<#delegate as std::convert::From<_>>::from(self), hasher) + } + } + } +} diff --git a/conjure-macros/src/lib.rs b/conjure-macros/src/lib.rs index 2f598374..a9cb9026 100644 --- a/conjure-macros/src/lib.rs +++ b/conjure-macros/src/lib.rs @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -//! Macros exposed by conjure-http. +//! Macros exposed by Conjure crates. //! //! Do not consume directly. #![warn(missing_docs)] @@ -20,6 +20,7 @@ use proc_macro::TokenStream; use syn::{Error, ItemTrait, TraitItem}; mod client; +mod derive_with; mod endpoints; mod path; @@ -417,6 +418,12 @@ pub fn endpoint(_attr: TokenStream, item: TokenStream) -> TokenStream { item } +#[doc(hidden)] +#[proc_macro_derive(DeriveWith, attributes(derive_with))] +pub fn derive_with(input: proc_macro::TokenStream) -> TokenStream { + derive_with::generate(input) +} + struct Errors(Vec); impl Errors { diff --git a/conjure-object/Cargo.toml b/conjure-object/Cargo.toml index 8cea27af..daab4536 100644 --- a/conjure-object/Cargo.toml +++ b/conjure-object/Cargo.toml @@ -15,13 +15,7 @@ js = ["uuid/js"] bytes = { version = "1.0", features = ["serde"] } base64 = "0.22" chrono = { version = "0.4.26", default-features = false, features = ["clock", "std", "serde"] } -educe = { version = "0.5", default-features = false, features = [ - "Hash", - "PartialEq", - "Eq", - "PartialOrd", - "Ord", -] } +conjure-macros = { version = "5.2.0", path = "../conjure-macros" } lazy_static = "1.0" ordered-float = { version = "5", features = ["serde"] } regex = { version = "1.3", default-features = false, features = ["std"] } diff --git a/conjure-object/src/private.rs b/conjure-object/src/private.rs index 65c3235a..a185f047 100644 --- a/conjure-object/src/private.rs +++ b/conjure-object/src/private.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub use educe::Educe; +pub use conjure_macros::DeriveWith; use ordered_float::OrderedFloat; use serde::de::{self, IntoDeserializer}; use serde::{Deserialize, Serialize}; @@ -27,6 +27,51 @@ use std::{fmt, mem}; use crate::plain::ParseEnumError; +pub struct DoubleWrapper(pub T); + +impl PartialEq for DoubleWrapper<&T> +where + T: DoubleOps, +{ + #[inline] + fn eq(&self, other: &Self) -> bool { + self.0.eq(other.0) + } +} + +impl Eq for DoubleWrapper<&T> where T: DoubleOps {} + +impl PartialOrd for DoubleWrapper<&T> +where + T: DoubleOps, +{ + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for DoubleWrapper<&T> +where + T: DoubleOps, +{ + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + self.0.cmp(other.0) + } +} + +impl Hash for DoubleWrapper<&T> +where + T: DoubleOps, +{ + #[inline] + fn hash(&self, state: &mut H) { + self.0.hash(state) + } +} + +// FIXME make private pub trait DoubleOps { fn cmp(&self, other: &Self) -> Ordering; @@ -148,15 +193,15 @@ where #[inline] fn cmp(&self, other: &Self) -> Ordering { self.iter() - .map(|(k, v)| (k, DoubleOpsWrapper(v))) - .cmp(other.iter().map(|(k, v)| (k, DoubleOpsWrapper(v)))) + .map(|(k, v)| (k, DoubleWrapper(v))) + .cmp(other.iter().map(|(k, v)| (k, DoubleWrapper(v)))) } #[inline] fn eq(&self, other: &Self) -> bool { self.iter() - .map(|(k, v)| (k, DoubleOpsWrapper(v))) - .eq(other.iter().map(|(k, v)| (k, DoubleOpsWrapper(v)))) + .map(|(k, v)| (k, DoubleWrapper(v))) + .eq(other.iter().map(|(k, v)| (k, DoubleWrapper(v)))) } #[inline] @@ -166,55 +211,11 @@ where { self.len().hash(hasher); for (k, v) in self { - (k, DoubleOpsWrapper(v)).hash(hasher); + (k, DoubleWrapper(v)).hash(hasher); } } } -struct DoubleOpsWrapper<'a, T>(&'a T); - -impl PartialEq for DoubleOpsWrapper<'_, T> -where - T: DoubleOps, -{ - #[inline] - fn eq(&self, other: &Self) -> bool { - self.0.eq(other.0) - } -} - -impl Eq for DoubleOpsWrapper<'_, T> where T: DoubleOps {} - -impl PartialOrd for DoubleOpsWrapper<'_, T> -where - T: DoubleOps, -{ - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for DoubleOpsWrapper<'_, T> -where - T: DoubleOps, -{ - #[inline] - fn cmp(&self, other: &Self) -> Ordering { - self.0.cmp(other.0) - } -} - -impl Hash for DoubleOpsWrapper<'_, T> -where - T: DoubleOps, -{ - #[inline] - fn hash(&self, state: &mut H) { - self.0.hash(state); - } -} - fn valid_enum_variant(s: &str) -> bool { if s.is_empty() { return false;