logline_core/ghost.rs
1#[cfg(not(feature = "std"))]
2use alloc::{boxed::Box, string::String};
3#[cfg(feature = "std")]
4use std::{boxed::Box, string::String};
5
6use crate::{LogLine, Status};
7
8/// Registro forense de um LogLine abandonado.
9///
10/// Preserva o LogLine original que foi abandonado (não commitado) para análise forense.
11/// O status é sempre `Ghost` e pode incluir uma razão opcional do abandono.
12///
13/// # Exemplo
14///
15/// ```rust
16/// use logline_core::*;
17///
18/// let line = LogLine::builder()
19/// .who("did:ubl:alice")
20/// .did(Verb::Deploy)
21/// .when(1_735_671_234)
22/// .if_ok(Outcome { label: "ok".into(), effects: vec![] })
23/// .if_doubt(Escalation { label: "doubt".into(), route_to: "qa".into() })
24/// .if_not(FailureHandling { label: "not".into(), action: "rollback".into() })
25/// .build_draft()?;
26///
27/// let ghost = line.abandon(Some("user_cancelled".into()))?;
28/// assert_eq!(ghost.status, Status::Ghost);
29/// assert_eq!(ghost.reason, Some("user_cancelled".into()));
30/// # Ok::<(), LogLineError>(())
31/// ```
32#[derive(Clone, Debug, PartialEq)]
33#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
34pub struct GhostRecord {
35 /// O LogLine original que foi abandonado.
36 pub inner: Box<LogLine>,
37 /// Status do registro (sempre `Ghost`).
38 pub status: Status,
39 /// Razão opcional do abandono (para análise forense).
40 pub reason: Option<String>,
41}
42
43impl GhostRecord {
44 /// Cria um `GhostRecord` a partir de um `LogLine` e uma razão opcional.
45 ///
46 /// O status do LogLine é alterado para `Ghost` antes de ser encapsulado.
47 pub fn from(mut line: LogLine, reason: Option<String>) -> Self {
48 line.status = Status::Ghost;
49 GhostRecord {
50 inner: Box::new(line),
51 status: Status::Ghost,
52 reason,
53 }
54 }
55}