logline_core/builder.rs
1#[cfg(not(feature = "std"))]
2use alloc::string::String;
3#[cfg(feature = "std")]
4use std::string::String;
5
6use crate::{Escalation, FailureHandling, LogLine, LogLineError, Outcome, Payload, Status, Verb};
7
8/// Builder para construir um `LogLine` passo a passo.
9///
10/// Use `LogLine::builder()` para criar um novo builder. Todos os campos
11/// obrigatórios devem ser fornecidos antes de chamar `build_draft()`.
12///
13/// # Exemplo
14///
15/// ```rust
16/// use logline_core::*;
17///
18/// let line = LogLine::builder()
19/// .who("did:ubl:alice")
20/// .did(Verb::Transfer)
21/// .this(Payload::Text("100 USD".into()))
22/// .when(1_735_671_234)
23/// .if_ok(Outcome { label: "transferred".into(), effects: vec!["emit_receipt".into()] })
24/// .if_doubt(Escalation { label: "verify".into(), route_to: "auditor".into() })
25/// .if_not(FailureHandling { label: "failed".into(), action: "compensate".into() })
26/// .build_draft()?;
27/// # Ok::<(), LogLineError>(())
28/// ```
29#[derive(Default)]
30pub struct LogLineBuilder {
31 who: Option<String>,
32 did: Option<Verb>,
33 this: Option<Payload>,
34 when: Option<u64>,
35 confirmed_by: Option<String>,
36 if_ok: Option<Outcome>,
37 if_doubt: Option<Escalation>,
38 if_not: Option<FailureHandling>,
39}
40
41impl LogLineBuilder {
42 pub fn new() -> Self {
43 Self::default()
44 }
45
46 /// Define o agente que executa a ação (DID futuro, ex: `did:ubl:...`).
47 pub fn who(mut self, v: impl Into<String>) -> Self {
48 self.who = Some(v.into());
49 self
50 }
51 /// Define o verbo da ação (canônico ou custom).
52 pub fn did(mut self, v: Verb) -> Self {
53 self.did = Some(v);
54 self
55 }
56 /// Define a carga útil da ação (payload).
57 pub fn this(mut self, v: Payload) -> Self {
58 self.this = Some(v);
59 self
60 }
61 /// Define o timestamp Unix em nanosegundos.
62 pub fn when(mut self, v: u64) -> Self {
63 self.when = Some(v);
64 self
65 }
66 /// Define a identidade que confirma a ação (opcional).
67 ///
68 /// Paper I: obrigatório para ações de Risk Level 3+ (L3+).
69 pub fn confirmed_by(mut self, v: impl Into<String>) -> Self {
70 self.confirmed_by = Some(v.into());
71 self
72 }
73 /// Define a consequência positiva obrigatória (invariant).
74 pub fn if_ok(mut self, v: Outcome) -> Self {
75 self.if_ok = Some(v);
76 self
77 }
78 /// Define a via de dúvida obrigatória (invariant).
79 pub fn if_doubt(mut self, v: Escalation) -> Self {
80 self.if_doubt = Some(v);
81 self
82 }
83 /// Define o fallback/erro obrigatório (invariant).
84 pub fn if_not(mut self, v: FailureHandling) -> Self {
85 self.if_not = Some(v);
86 self
87 }
88
89 /// Constrói um DRAFT válido (invariants obrigatórios presentes).
90 ///
91 /// Valida que todos os campos obrigatórios estão presentes e cria um `LogLine`
92 /// com status `Draft`. Os invariants são verificados antes de retornar.
93 ///
94 /// # Erros
95 ///
96 /// - `LogLineError::MissingField` se algum campo obrigatório estiver faltando
97 /// - `LogLineError::MissingInvariant` se algum invariant estiver faltando ou vazio
98 ///
99 /// # Campos obrigatórios
100 ///
101 /// - `who`: identidade do agente
102 /// - `did`: verbo da ação
103 /// - `when`: timestamp
104 /// - `if_ok`: consequência positiva
105 /// - `if_doubt`: via de dúvida
106 /// - `if_not`: fallback/erro
107 pub fn build_draft(self) -> Result<LogLine, LogLineError> {
108 let line = LogLine {
109 who: self.who.ok_or(LogLineError::MissingField("who"))?,
110 did: self.did.ok_or(LogLineError::MissingField("did"))?,
111 this: self.this.unwrap_or(Payload::None),
112 when: self.when.ok_or(LogLineError::MissingField("when"))?,
113 confirmed_by: self.confirmed_by,
114 if_ok: self.if_ok.ok_or(LogLineError::MissingInvariant("if_ok"))?,
115 if_doubt: self
116 .if_doubt
117 .ok_or(LogLineError::MissingInvariant("if_doubt"))?,
118 if_not: self
119 .if_not
120 .ok_or(LogLineError::MissingInvariant("if_not"))?,
121 status: Status::Draft,
122 };
123 line.verify_invariants()?;
124 Ok(line)
125 }
126}