diff --git a/README.md b/README.md index ab9c46c..8297872 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ async fn extended_example() { #### Getting a Struct from a Provider -It is possible to extract a struct from the provider. Internally, this SDK defines a type `StructValue` to store any structure value. The `client.get_struct_value()` functions takes a type parameter `T`. It will try to parse `StructValue` resolved by the provider to `T`, as long as `T` implements trait `FromStructValue`. +It is possible to extract a struct from the provider. Internally, this SDK defines a type `StructValue` to store any structure value. The `client.get_struct_value()` functions takes a type parameter `T`. It will try to parse `StructValue` resolved by the provider to `T`, as long as `T` implements trait `TryFrom`. You can pass in a type that satisfies this trait bound. When the conversion fails, it returns an `Err` with `EvaluationReason::TypeMismatch`. diff --git a/src/api/client.rs b/src/api/client.rs index 6cf188e..69877cf 100644 --- a/src/api/client.rs +++ b/src/api/client.rs @@ -25,13 +25,6 @@ pub struct Client { global_evaluation_context: GlobalEvaluationContext, } -/// The trait that converts a [`StructValue`] to a custom type. -/// It is used to return a custom type from `get_struct_value` and `get_string_details`. -pub trait FromStructValue { - /// Construct type with given `value`. - fn from_struct_value(value: &StructValue) -> anyhow::Result; -} - impl Client { /// Create a new [`Client`] instance. pub fn new( @@ -140,7 +133,7 @@ impl Client { /// If the resolution fails, the `default_value` is returned. /// The required type should implement [`From`] trait. #[allow(unused_variables)] - pub async fn get_struct_value( + pub async fn get_struct_value>( &self, flag_key: &str, evaluation_context: Option<&EvaluationContext>, @@ -154,7 +147,7 @@ impl Client { .resolve_struct_value(flag_key, &context) .await?; - match T::from_struct_value(&result.value) { + match T::try_from(result.value) { Ok(t) => Ok(t), Err(error) => Err(EvaluationError { code: EvaluationErrorCode::TypeMismatch, @@ -242,7 +235,7 @@ impl Client { /// Return the [`EvaluationDetails`] with given `flag_key`, `evaluation_context` and /// `evaluation_options`. #[allow(unused_variables)] - pub async fn get_struct_details( + pub async fn get_struct_details>( &self, flag_key: &str, evaluation_context: Option<&EvaluationContext>, @@ -256,7 +249,7 @@ impl Client { .resolve_struct_value(flag_key, &context) .await?; - match T::from_struct_value(&result.value) { + match T::try_from(result.value) { Ok(value) => Ok(EvaluationDetails { flag_key: flag_key.to_string(), value, @@ -322,8 +315,6 @@ mod tests { Client, EvaluationReason, FlagMetadata, StructValue, }; - use super::FromStructValue; - #[spec( number = "1.2.2", text = "The client interface MUST define a metadata member or accessor, containing an immutable name field or accessor of type string, which corresponds to the name value supplied during client creation." @@ -339,16 +330,23 @@ mod tests { name: String, } - impl FromStructValue for Student { - fn from_struct_value(value: &StructValue) -> anyhow::Result { + impl TryFrom for Student { + type Error = String; + + fn try_from(value: StructValue) -> Result { Ok(Student { - id: value.fields.get("id").unwrap().as_i64().unwrap(), + id: value + .fields + .get("id") + .ok_or("id not provided")? + .as_i64() + .ok_or("id is not a valid number")?, name: value .fields .get("name") - .unwrap() + .ok_or("name not provided")? .as_str() - .unwrap() + .ok_or("name is not a valid string")? .to_string(), }) } diff --git a/src/api/mod.rs b/src/api/mod.rs index 58ef818..6677c6d 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -2,7 +2,7 @@ mod api; pub use api::OpenFeature; mod client; -pub use client::{Client, ClientMetadata, FromStructValue}; +pub use client::{Client, ClientMetadata}; mod provider_registry;