mysten_common/rpc_format/
to_format.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::rpc_format::Format;
5use crate::rpc_format::Meter;
6use crate::rpc_format::MeterError;
7
8/// Render `self` into any [`Format`] sink. Designed for use by code that wants to expose a
9/// statically typed Rust value (e.g. each field of `ProtocolConfig`) through one of the
10/// `Format`-implementing wire types (`serde_json::Value`, `prost_types::Value`, etc.) without
11/// having to enumerate the destination type at the call site.
12///
13/// Integer types wider than 32 bits are rendered through [`Format::string`] rather than
14/// [`Format::number`] because `Format::number` is defined to take `u32`. This also matches the
15/// convention used elsewhere in the codebase to dodge the IEEE-754 precision loss that bites
16/// JavaScript clients consuming JSON numbers above 2^53.
17pub trait ToFormat {
18    fn to_format<F: Format, M: Meter>(&self, meter: &mut M) -> Result<F, MeterError>;
19}
20
21impl ToFormat for bool {
22    fn to_format<F: Format, M: Meter>(&self, meter: &mut M) -> Result<F, MeterError> {
23        F::bool(meter, *self)
24    }
25}
26
27impl ToFormat for u8 {
28    fn to_format<F: Format, M: Meter>(&self, meter: &mut M) -> Result<F, MeterError> {
29        F::number(meter, u32::from(*self))
30    }
31}
32
33impl ToFormat for u16 {
34    fn to_format<F: Format, M: Meter>(&self, meter: &mut M) -> Result<F, MeterError> {
35        F::number(meter, u32::from(*self))
36    }
37}
38
39impl ToFormat for u32 {
40    fn to_format<F: Format, M: Meter>(&self, meter: &mut M) -> Result<F, MeterError> {
41        F::number(meter, *self)
42    }
43}
44
45impl ToFormat for u64 {
46    fn to_format<F: Format, M: Meter>(&self, meter: &mut M) -> Result<F, MeterError> {
47        F::string(meter, self.to_string())
48    }
49}
50
51impl ToFormat for u128 {
52    fn to_format<F: Format, M: Meter>(&self, meter: &mut M) -> Result<F, MeterError> {
53        F::string(meter, self.to_string())
54    }
55}
56
57impl ToFormat for usize {
58    fn to_format<F: Format, M: Meter>(&self, meter: &mut M) -> Result<F, MeterError> {
59        // Treat `usize` as potentially wider than 32 bits — it's `u64` on every target we ship.
60        F::string(meter, self.to_string())
61    }
62}
63
64impl ToFormat for String {
65    fn to_format<F: Format, M: Meter>(&self, meter: &mut M) -> Result<F, MeterError> {
66        F::string(meter, self.clone())
67    }
68}
69
70impl ToFormat for &str {
71    fn to_format<F: Format, M: Meter>(&self, meter: &mut M) -> Result<F, MeterError> {
72        F::string(meter, (*self).to_owned())
73    }
74}
75
76impl<T: ToFormat> ToFormat for Option<T> {
77    fn to_format<F: Format, M: Meter>(&self, meter: &mut M) -> Result<F, MeterError> {
78        match self {
79            Some(inner) => inner.to_format(meter),
80            None => F::null(meter),
81        }
82    }
83}
84
85impl<T: ToFormat> ToFormat for Vec<T> {
86    fn to_format<F: Format, M: Meter>(&self, meter: &mut M) -> Result<F, MeterError> {
87        let mut out = F::Vec::default();
88        // Scope the nested meter so it's dropped before we reuse `meter` to finalize the vec.
89        {
90            let mut nested = meter.nest()?;
91            for item in self {
92                let elem = item.to_format::<F, _>(&mut nested)?;
93                F::vec_push_element(&mut nested, &mut out, elem)?;
94            }
95        }
96        F::vec(meter, out)
97    }
98}
99
100impl<T: ToFormat> ToFormat for [T] {
101    fn to_format<F: Format, M: Meter>(&self, meter: &mut M) -> Result<F, MeterError> {
102        let mut out = F::Vec::default();
103        {
104            let mut nested = meter.nest()?;
105            for item in self {
106                let elem = item.to_format::<F, _>(&mut nested)?;
107                F::vec_push_element(&mut nested, &mut out, elem)?;
108            }
109        }
110        F::vec(meter, out)
111    }
112}
113
114macro_rules! impl_to_format_for_tuple {
115    ($($name:ident),+) => {
116        impl<$($name: ToFormat),+> ToFormat for ($($name,)+) {
117            fn to_format<F: Format, M: Meter>(&self, meter: &mut M) -> Result<F, MeterError> {
118                #[allow(non_snake_case)]
119                let ($($name,)+) = self;
120                let mut out = F::Vec::default();
121                {
122                    let mut nested = meter.nest()?;
123                    $(
124                        let elem = $name.to_format::<F, _>(&mut nested)?;
125                        F::vec_push_element(&mut nested, &mut out, elem)?;
126                    )+
127                }
128                F::vec(meter, out)
129            }
130        }
131    };
132}
133
134impl_to_format_for_tuple!(T1, T2);
135impl_to_format_for_tuple!(T1, T2, T3);
136impl_to_format_for_tuple!(T1, T2, T3, T4);