1#![allow(clippy::large_enum_variant)]
2#![allow(clippy::doc_overindented_list_items)]
3
4use google::rpc::bad_request::FieldViolation;
5use sui::rpc::v2beta2::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: 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 field = field.as_ref();
45 self.field_violation = self.field_violation.nested(field);
46 self
47 }
48
49 pub fn nested_at<T: AsRef<str>>(mut self, field: T, index: usize) -> Self {
50 let field = field.as_ref();
51 self.field_violation = self.field_violation.nested_at(field, 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: FieldViolation::new(field).with_reason(ErrorReason::FieldMissing),
60 source: None,
61 }
62 }
63
64 pub fn invalid<T: AsRef<str>, E: Into<BoxError>>(field: T, error: E) -> Self {
65 let field = field.as_ref();
66 let error = error.into();
67
68 Self {
69 field_violation: FieldViolation::new(field)
70 .with_reason(ErrorReason::FieldInvalid)
71 .with_description(error.to_string()),
72 source: Some(error),
73 }
74 }
75
76 pub fn field_violation(&self) -> &FieldViolation {
77 &self.field_violation
78 }
79}
80
81pub fn timestamp_ms_to_proto(timestamp_ms: u64) -> prost_types::Timestamp {
86 let timestamp = std::time::Duration::from_millis(timestamp_ms);
87 prost_types::Timestamp {
88 seconds: timestamp.as_secs() as i64,
89 nanos: timestamp.subsec_nanos() as i32,
90 }
91}
92
93#[allow(clippy::result_large_err)]
94pub fn proto_to_timestamp_ms(timestamp: prost_types::Timestamp) -> Result<u64, TryFromProtoError> {
95 let seconds = std::time::Duration::from_secs(
96 timestamp
97 .seconds
98 .try_into()
99 .map_err(|e| TryFromProtoError::invalid("seconds", e))?,
100 );
101 let nanos = std::time::Duration::from_nanos(
102 timestamp
103 .nanos
104 .try_into()
105 .map_err(|e| TryFromProtoError::invalid("nanos", e))?,
106 );
107
108 (seconds + nanos)
109 .as_millis()
110 .try_into()
111 .map_err(|e| TryFromProtoError::invalid("seconds + nanos", e))
112}