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}