sui_rpc/proto/
mod.rs

1#![allow(clippy::large_enum_variant)]
2#![allow(clippy::doc_overindented_list_items)]
3
4use google::rpc::bad_request::FieldViolation;
5use sui::rpc::v2::ErrorReason;
6
7pub mod google;
8pub mod sui;
9
10type BoxError = Box<dyn std::error::Error + Send + Sync + 'static>;
11
12#[derive(Debug)]
13pub struct TryFromProtoError {
14    field_violation: Box<FieldViolation>,
15    source: Option<BoxError>,
16}
17
18impl std::fmt::Display for TryFromProtoError {
19    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20        write!(f, "error converting from protobuf: ")?;
21
22        write!(f, "field: {}", self.field_violation.field)?;
23
24        if !self.field_violation.reason.is_empty() {
25            write!(f, " reason: {}", self.field_violation.reason)?;
26        }
27
28        if !self.field_violation.description.is_empty() {
29            write!(f, " description: {}", self.field_violation.description)?;
30        }
31
32        Ok(())
33    }
34}
35
36impl std::error::Error for TryFromProtoError {
37    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
38        self.source.as_deref().map(|s| s as _)
39    }
40}
41
42impl TryFromProtoError {
43    pub fn nested<T: AsRef<str>>(mut self, field: T) -> Self {
44        let fv = std::mem::take(&mut *self.field_violation);
45        *self.field_violation = fv.nested(field.as_ref());
46        self
47    }
48
49    pub fn nested_at<T: AsRef<str>>(mut self, field: T, index: usize) -> Self {
50        let fv = std::mem::take(&mut *self.field_violation);
51        *self.field_violation = fv.nested_at(field.as_ref(), index);
52        self
53    }
54
55    pub fn missing<T: AsRef<str>>(field: T) -> Self {
56        let field = field.as_ref();
57
58        Self {
59            field_violation: Box::new(
60                FieldViolation::new(field).with_reason(ErrorReason::FieldMissing),
61            ),
62            source: None,
63        }
64    }
65
66    pub fn invalid<T: AsRef<str>, E: Into<BoxError>>(field: T, error: E) -> Self {
67        let field = field.as_ref();
68        let error = error.into();
69
70        Self {
71            field_violation: Box::new(
72                FieldViolation::new(field)
73                    .with_reason(ErrorReason::FieldInvalid)
74                    .with_description(error.to_string()),
75            ),
76            source: Some(error),
77        }
78    }
79
80    pub fn field_violation(&self) -> &FieldViolation {
81        &self.field_violation
82    }
83}
84
85//
86// TimeStamp
87//
88
89pub fn timestamp_ms_to_proto(timestamp_ms: u64) -> prost_types::Timestamp {
90    let timestamp = std::time::Duration::from_millis(timestamp_ms);
91    prost_types::Timestamp {
92        seconds: timestamp.as_secs() as i64,
93        nanos: timestamp.subsec_nanos() as i32,
94    }
95}
96
97pub fn proto_to_timestamp_ms(timestamp: prost_types::Timestamp) -> Result<u64, TryFromProtoError> {
98    let seconds = std::time::Duration::from_secs(
99        timestamp
100            .seconds
101            .try_into()
102            .map_err(|e| TryFromProtoError::invalid("seconds", e))?,
103    );
104    let nanos = std::time::Duration::from_nanos(
105        timestamp
106            .nanos
107            .try_into()
108            .map_err(|e| TryFromProtoError::invalid("nanos", e))?,
109    );
110
111    (seconds + nanos)
112        .as_millis()
113        .try_into()
114        .map_err(|e| TryFromProtoError::invalid("seconds + nanos", e))
115}