restate_sdk_shared_core/
fmt.rs

1use crate::CommandType;
2use std::fmt;
3use std::sync::OnceLock;
4
5pub trait CommandFormatter: Send + Sync + fmt::Debug + 'static {
6    fn ty_display(&self, ty: CommandType) -> &'static str;
7}
8
9static GLOBAL_COMMAND_FORMATTER: OnceLock<Box<dyn CommandFormatter>> = OnceLock::new();
10
11// Public function for the crate user to set the formatter
12pub fn set_error_formatter(formatter: impl CommandFormatter + 'static) {
13    GLOBAL_COMMAND_FORMATTER
14        .set(Box::new(formatter))
15        .expect("Error formatter already set! It can only be set once.");
16}
17
18#[derive(Debug)]
19struct DefaultCommandFormatter;
20
21impl CommandFormatter for DefaultCommandFormatter {
22    fn ty_display(&self, ty: CommandType) -> &'static str {
23        match ty {
24            CommandType::Input => "handler input",
25            CommandType::Output => "handler return",
26            CommandType::GetState => "get state",
27            CommandType::GetStateKeys => "get state keys",
28            CommandType::SetState => "set state",
29            CommandType::ClearState => "clear state",
30            CommandType::ClearAllState => "clear all state",
31            CommandType::GetPromise => "get promise",
32            CommandType::PeekPromise => "peek promise",
33            CommandType::CompletePromise => "complete promise",
34            CommandType::Sleep => "sleep",
35            CommandType::Call => "call",
36            CommandType::OneWayCall => "one way call/send",
37            CommandType::SendSignal => "send signal",
38            CommandType::Run => "run",
39            CommandType::AttachInvocation => "attach invocation",
40            CommandType::GetInvocationOutput => "get invocation output",
41            CommandType::CompleteAwakeable => "complete awakeable",
42            CommandType::CancelInvocation => "cancel invocation",
43        }
44    }
45}
46
47pub(crate) fn display_command_ty(command_type: CommandType) -> &'static str {
48    if let Some(custom_formatter) = GLOBAL_COMMAND_FORMATTER.get() {
49        custom_formatter.ty_display(command_type)
50    } else {
51        DefaultCommandFormatter.ty_display(command_type)
52    }
53}
54
55pub(crate) struct DiffFormatter<'a, 'b> {
56    fmt: &'a mut fmt::Formatter<'b>,
57    indentation: &'static str,
58}
59
60impl<'a, 'b: 'a> DiffFormatter<'a, 'b> {
61    pub(crate) fn new(fmt: &'a mut fmt::Formatter<'b>, indentation: &'static str) -> Self {
62        Self { fmt, indentation }
63    }
64
65    pub(crate) fn write_diff(
66        &mut self,
67        field_name: &'static str,
68        actual: impl fmt::Display,
69        expected: impl fmt::Display,
70    ) -> fmt::Result {
71        write!(
72            self.fmt,
73            "\n{}{field_name}: {actual} != {expected}",
74            self.indentation
75        )
76    }
77
78    pub(crate) fn write_bytes_diff(
79        &mut self,
80        field_name: &'static str,
81        actual: &[u8],
82        expected: &[u8],
83    ) -> fmt::Result {
84        write!(self.fmt, "\n{}{field_name}: ", self.indentation)?;
85        match (std::str::from_utf8(actual), std::str::from_utf8(expected)) {
86            (Ok(actual), Ok(expected)) => {
87                write!(self.fmt, "'{actual}' != '{expected}'",)
88            }
89            (Ok(actual), Err(_)) => {
90                write!(self.fmt, "'{actual}' != {expected:?}")
91            }
92            (Err(_), Ok(expected)) => {
93                write!(self.fmt, "{actual:?} != '{expected}'")
94            }
95            (Err(_), Err(_)) => {
96                write!(self.fmt, "{actual:?} != {expected:?}")
97            }
98        }
99    }
100}