///|
/// Providers return this transport-independent resolution; the client validates
/// its value and substitutes the caller default on every error path.
pub(all) struct Resolution {
value : FlagValue
reason : String
variant : String?
error : SdkError?
metadata : FlagMetadata
}
///|
pub fn Resolution::success(
value : FlagValue,
reason~ : String = "UNKNOWN",
variant~ : String? = None,
metadata~ : FlagMetadata = FlagMetadata::empty(),
) -> Resolution {
{ value, reason, variant, error: None, metadata: metadata.copy(), }
}
///|
pub fn Resolution::failure(default : FlagValue, error : SdkError) -> Resolution {
{
value: default,
reason: "ERROR",
variant: None,
error: Some(error),
metadata: FlagMetadata::empty(),
}
}
///|
pub fn Resolution::checked(
self : Resolution,
expected : FlagType,
default : FlagValue,
) -> Resolution {
if self.error is Some(error) {
return {
..Resolution::failure(default.copy(), error),
metadata: self.metadata.copy(),
}
}
if self.value.flag_type() != expected {
return Resolution::failure(
default.copy(),
SdkError::new(TypeMismatch, "provider returned a different flag type"),
)
}
match self.value.validate() {
Err(error) => Resolution::failure(default.copy(), error)
Ok(_) =>
{ ..self, value: self.value.copy(), metadata: self.metadata.copy(), }
}
}
///|
pub(all) struct EvaluationDetails {
flag_key : String
value : FlagValue
reason : String
variant : String?
error : SdkError?
metadata : FlagMetadata
}
///|
pub fn EvaluationDetails::from_resolution(
flag_key : String,
resolution : Resolution,
) -> EvaluationDetails {
{
flag_key,
value: resolution.value,
reason: resolution.reason,
variant: resolution.variant,
error: resolution.error,
metadata: resolution.metadata.copy(),
}
}
///|
pub fn EvaluationDetails::copy(self : EvaluationDetails) -> EvaluationDetails {
{ ..self, value: self.value.copy(), metadata: self.metadata.copy(), }
}
///|
pub fn EvaluationDetails::is_error(self : EvaluationDetails) -> Bool {
self.error is Some(_)
}
///|
pub fn EvaluationDetails::to_json(self : EvaluationDetails) -> Json {
let result : Map[String, Json] = {
"flagKey": Json::string(self.flag_key),
"value": self.value.to_json(),
"reason": Json::string(self.reason),
"flagMetadata": self.metadata.to_json(),
}
match self.variant {
Some(variant) => result["variant"] = Json::string(variant)
None => ()
}
match self.error {
Some(error) => {
result["errorCode"] = Json::string(error.code.name())
result["errorMessage"] = Json::string(error.message)
}
None => ()
}
Json::object(result)
}
///|
/// Typed results retain the shared diagnostic model without casting numeric types.
pub(all) struct Evaluation[T] {
value : T
details : EvaluationDetails
}
///|
pub fn[T] Evaluation::is_error(self : Evaluation[T]) -> Bool {
self.details.is_error()
}