cli

Command-line interface for Radroots
git clone https://radroots.dev/git/cli.git
Log | Files | Refs | README | LICENSE

result.rs (3119B)


      1 use std::fmt::Debug;
      2 
      3 use serde::Serialize;
      4 use serde_json::Value;
      5 
      6 use super::error::OperationAdapterError;
      7 use super::request::OperationData;
      8 use crate::out::envelope::{
      9     EnvelopeContext, NextAction, OutputEnvelope, OutputWarning, next_actions_from_result_value,
     10 };
     11 use crate::registry::{OperationSpec, get_operation};
     12 
     13 pub trait OperationResultPayload: Debug + Clone + PartialEq + Serialize + 'static {
     14     const OPERATION_ID: &'static str;
     15     const RESULT_TYPE: &'static str;
     16 }
     17 
     18 pub trait OperationResultData: OperationResultPayload + Sized {
     19     fn from_data(data: OperationData) -> Self;
     20 
     21     fn from_value(value: Value) -> Self {
     22         Self::from_data(value_to_data(value))
     23     }
     24 
     25     fn from_serializable<T: Serialize>(value: &T) -> Result<Self, OperationAdapterError> {
     26         Ok(Self::from_value(serde_json::to_value(value).map_err(
     27             |error| OperationAdapterError::Serialization(error.to_string()),
     28         )?))
     29     }
     30 }
     31 
     32 #[derive(Debug, Clone, PartialEq)]
     33 pub struct OperationResult<P: OperationResultPayload> {
     34     pub spec: &'static OperationSpec,
     35     pub payload: P,
     36     pub warnings: Vec<OutputWarning>,
     37     pub next_actions: Vec<NextAction>,
     38 }
     39 
     40 impl<P: OperationResultPayload> OperationResult<P> {
     41     pub fn new(payload: P) -> Result<Self, OperationAdapterError> {
     42         let spec = get_operation(P::OPERATION_ID)
     43             .ok_or_else(|| OperationAdapterError::UnknownOperation(P::OPERATION_ID.to_owned()))?;
     44         if spec.rust_result != P::RESULT_TYPE {
     45             return Err(OperationAdapterError::ResultTypeMismatch {
     46                 operation_id: P::OPERATION_ID.to_owned(),
     47                 registry_result: spec.rust_result.to_owned(),
     48                 adapter_result: P::RESULT_TYPE.to_owned(),
     49             });
     50         }
     51         Ok(Self {
     52             spec,
     53             payload,
     54             warnings: Vec::new(),
     55             next_actions: Vec::new(),
     56         })
     57     }
     58 
     59     pub fn operation_id(&self) -> &'static str {
     60         P::OPERATION_ID
     61     }
     62 
     63     pub fn result_type_name(&self) -> &'static str {
     64         P::RESULT_TYPE
     65     }
     66 
     67     pub fn to_envelope(
     68         &self,
     69         context: EnvelopeContext,
     70     ) -> Result<OutputEnvelope, OperationAdapterError> {
     71         let result = serde_json::to_value(&self.payload)
     72             .map_err(|error| OperationAdapterError::Serialization(error.to_string()))?;
     73         let next_actions = if self.next_actions.is_empty() {
     74             next_actions_from_result(&result)
     75         } else {
     76             self.next_actions.clone()
     77         };
     78         let mut envelope = OutputEnvelope::success(self.operation_id(), result, context);
     79         envelope.warnings = self.warnings.clone();
     80         envelope.next_actions = next_actions;
     81         Ok(envelope)
     82     }
     83 }
     84 
     85 fn next_actions_from_result(result: &Value) -> Vec<NextAction> {
     86     next_actions_from_result_value(result)
     87 }
     88 
     89 pub(crate) fn value_to_data(value: Value) -> OperationData {
     90     match value {
     91         Value::Object(map) => map,
     92         other => {
     93             let mut map = OperationData::new();
     94             map.insert("value".to_owned(), other);
     95             map
     96         }
     97     }
     98 }