//! Stable typed outcomes for the Kaptan configuration microservice. use kaptan_config::{ConfigState, ConfigViolation, FieldId}; use kaptan_err_reportable::KaptanError; /// Operation reported in an authoritative result record. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Operation { /// Query/read operation. Query, /// Begin transaction. Begin, /// Scalar write. Set, /// Whole-candidate validation. Validate, /// Durable commit. Commit, /// Transaction abort. Abort, } /// Stable result classification. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum ResultKind { /// The operation was accepted. Accepted, /// A full snapshot committed but requires restart before activation. CommittedRestartRequired, /// The operation was rejected without an active-state transition. Rejected, } /// Compact protocol error code. Detail belongs in [`ConfigViolation`] when a /// configuration invariant was responsible. #[derive(Clone, Copy, Debug, Eq, PartialEq, KaptanError)] pub enum ProtocolError { /// The request target did not match this component. #[kaptan_error(id = 2001)] BadTarget, /// The configuration lease or single transaction slot is occupied. #[kaptan_error(id = 2002)] SessionBusy, /// The session is unknown, expired, or belongs to a different principal. #[kaptan_error(id = 2003)] InvalidSession, /// Reusing one request ID with different content is forbidden. #[kaptan_error(id = 2004)] RequestConflict, /// The request was not based on the current transaction revision. #[kaptan_error(id = 2005)] StaleRevision, /// A command is invalid in the current lifecycle state. #[kaptan_error(id = 2006)] BadState, /// The field is not present in this schema. #[kaptan_error(id = 2007)] UnknownField(FieldId), /// A query requested an empty or out-of-range descriptor span. #[kaptan_error(id = 2008)] InvalidQuery, /// The typed setter does not match the field descriptor. #[kaptan_error(id = 2009)] TypeMismatch(FieldId), /// A local or complete validation issue. #[kaptan_error(id = 2010)] Violation(ConfigViolation), /// Persistence failed after a complete validation pass. #[kaptan_error(id = 2011)] StorageFailure, /// The adapter reached an impossible internal state. #[kaptan_error(id = 2012)] Internal, } /// Authoritative completion for one request. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct ConfigReply { /// Client request identity. pub request_id: u32, /// The current session, or zero when none exists. pub session_id: u32, /// The transaction revision, or zero when no transaction exists. pub revision: u32, /// Completed operation. pub operation: Operation, /// High-level result. pub result: ResultKind, /// Exact typed failure, if rejected. pub error: Option, /// Current lifecycle state after handling the request. pub state: ConfigState, } impl ConfigReply { /// Stable primary field for the wire response, or the reserved sentinel. pub const fn primary_field(self) -> u16 { match self.error { Some(ProtocolError::Violation(violation)) => match violation.primary() { Some(field) => field.get(), None => u16::MAX, }, Some(ProtocolError::UnknownField(field)) | Some(ProtocolError::TypeMismatch(field)) => { field.get() } _ => u16::MAX, } } /// Stable related field for the wire response, or the reserved sentinel. pub const fn related_field(self) -> u16 { match self.error { Some(ProtocolError::Violation(violation)) => match violation.related_field() { Some(field) => field.get(), None => u16::MAX, }, _ => u16::MAX, } } /// Stable validation-rule code, or zero when no validation rule applies. pub const fn validation_rule(self) -> u16 { match self.error { Some(ProtocolError::Violation(violation)) => violation.rule().code(), _ => 0, } } }