• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tari-project / tari_utilities / 5543897128

pending completion
5543897128

push

github

web-flow
feat: ledger compatability (#54)

This PR is to add no_std support. This is in-line to ensure that
tari_utilities can compile for nonstandard tier 1 rust targets. This is
required for the push to ensure we can create a ledger-compatible
library and allow us to run some of the handy utilities from this crate.

The changes can be summarized in the following:

- Made the library `no_std`
- Upgraded borsch to version 0.10, up from 0.9
- Added feature flags to hide crates and features that are not possible
on `no_std` targets

Feature flags added:

- `std` - This will allow epoch_time, encoding and safe_array
- `zero` - This will include zeroize support
- `serialize` - This will include support for serde
- `borsh` - This will include support for borsh
- `default` - This will include all feature flags and allow all
utilities.

---------

Co-authored-by: stringhandler <stringhandler@gmail.com>

31 of 31 new or added lines in 7 files covered. (100.0%)

779 of 814 relevant lines covered (95.7%)

2.65 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.06
/src/message_format.rs
1
// Copyright 2018 The Tari Project
2
//
3
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
4
// following conditions are met:
5
//
6
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
7
// disclaimer.
8
//
9
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
10
// following disclaimer in the documentation and/or other materials provided with the distribution.
11
//
12
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
13
// products derived from this software without specific prior written permission.
14
//
15
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
16
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
20
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
21
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22

23
//! A `MessageFormat` trait that handles conversion from and to binary, json, or base64.
24

25
use alloc::{string::String, vec::Vec};
26

27
use base64;
28
use serde::{de::DeserializeOwned, Deserialize, Serialize};
29
use serde_json;
30
use snafu::prelude::*;
31

32
/// Errors for [MessageFormat] trait.
33
#[derive(Debug, Snafu)]
×
34
#[allow(missing_docs)]
35
pub enum MessageFormatError {
36
    #[snafu(display("An error occurred serialising an object into binary"))]
37
    BinarySerializeError {},
38
    #[snafu(display("An error occurred deserialising binary data into an object"))]
39
    BinaryDeserializeError {},
40
    #[snafu(display("An error occurred de-/serialising an object from/into JSON"))]
41
    JSONError {},
42
    #[snafu(display("An error occurred deserialising an object from Base64"))]
43
    Base64DeserializeError {},
44
}
45

46
/// Trait for converting to/from binary/json/base64.
47
pub trait MessageFormat: Sized {
48
    /// Convert to binary.
49
    fn to_binary(&self) -> Result<Vec<u8>, MessageFormatError>;
50
    /// Convert to json.
51
    fn to_json(&self) -> Result<String, MessageFormatError>;
52
    /// Convert to base64.
53
    fn to_base64(&self) -> Result<String, MessageFormatError>;
54

55
    /// Convert from binary.
56
    fn from_binary(msg: &[u8]) -> Result<Self, MessageFormatError>;
57
    /// Convert from json.
58
    fn from_json(msg: &str) -> Result<Self, MessageFormatError>;
59
    /// Convert from base64.
60
    fn from_base64(msg: &str) -> Result<Self, MessageFormatError>;
61
}
62

63
impl<T> MessageFormat for T
64
where T: DeserializeOwned + Serialize
65
{
66
    fn to_binary(&self) -> Result<Vec<u8>, MessageFormatError> {
4✔
67
        bincode::serialize(self).map_err(|_| MessageFormatError::BinarySerializeError {})
4✔
68
    }
4✔
69

70
    fn to_json(&self) -> Result<String, MessageFormatError> {
2✔
71
        serde_json::to_string(self).map_err(|_| MessageFormatError::JSONError {})
2✔
72
    }
2✔
73

74
    fn to_base64(&self) -> Result<String, MessageFormatError> {
2✔
75
        let val = self.to_binary()?;
2✔
76
        Ok(base64::encode(val))
2✔
77
    }
2✔
78

79
    fn from_binary(msg: &[u8]) -> Result<Self, MessageFormatError> {
6✔
80
        bincode::deserialize(msg).map_err(|_| MessageFormatError::BinaryDeserializeError {})
6✔
81
    }
6✔
82

83
    fn from_json(msg: &str) -> Result<Self, MessageFormatError> {
3✔
84
        let mut de = serde_json::Deserializer::from_reader(msg.as_bytes());
3✔
85
        Deserialize::deserialize(&mut de).map_err(|_| MessageFormatError::JSONError {})
3✔
86
    }
3✔
87

88
    fn from_base64(msg: &str) -> Result<Self, MessageFormatError> {
4✔
89
        let buf = base64::decode(msg).map_err(|_| MessageFormatError::Base64DeserializeError {})?;
4✔
90
        Self::from_binary(&buf)
3✔
91
    }
4✔
92
}
93

94
#[cfg(test)]
95
mod test {
96
    use alloc::{boxed::Box, string::ToString};
97

98
    use serde::{Deserialize, Serialize};
99

100
    use super::*;
101

102
    #[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
32✔
103
    struct TestMessage {
104
        key: String,
105
        value: u64,
106
        sub_message: Option<Box<TestMessage>>,
107
    }
108

109
    impl TestMessage {
110
        pub fn new(key: &str, value: u64) -> TestMessage {
5✔
111
            TestMessage {
5✔
112
                key: key.to_string(),
5✔
113
                value,
5✔
114
                sub_message: None,
5✔
115
            }
5✔
116
        }
5✔
117

118
        pub fn set_sub_message(&mut self, msg: TestMessage) {
1✔
119
            self.sub_message = Some(Box::new(msg));
1✔
120
        }
1✔
121
    }
122

123
    #[test]
1✔
124
    fn binary_simple() {
1✔
125
        let val = TestMessage::new("twenty", 20);
1✔
126
        let msg = val.to_binary().unwrap();
1✔
127
        assert_eq!(
1✔
128
            msg,
1✔
129
            b"\x06\x00\x00\x00\x00\x00\x00\x00\x74\x77\x65\x6e\x74\x79\x14\x00\x00\x00\x00\x00\x00\x00\x00"
1✔
130
        );
1✔
131
        let val2 = TestMessage::from_binary(&msg).unwrap();
1✔
132
        assert_eq!(val, val2);
1✔
133
    }
1✔
134

135
    #[test]
1✔
136
    fn base64_simple() {
1✔
137
        let val = TestMessage::new("twenty", 20);
1✔
138
        let msg = val.to_base64().unwrap();
1✔
139
        assert_eq!(msg, "BgAAAAAAAAB0d2VudHkUAAAAAAAAAAA=");
1✔
140
        let val2 = TestMessage::from_base64(&msg).unwrap();
1✔
141
        assert_eq!(val, val2);
1✔
142
    }
1✔
143

144
    #[test]
1✔
145
    fn json_simple() {
1✔
146
        let val = TestMessage::new("twenty", 20);
1✔
147
        let msg = val.to_json().unwrap();
1✔
148
        assert_eq!(msg, "{\"key\":\"twenty\",\"value\":20,\"sub_message\":null}");
1✔
149
        let val2 = TestMessage::from_json(&msg).unwrap();
1✔
150
        assert_eq!(val, val2);
1✔
151
    }
1✔
152

153
    #[test]
1✔
154
    fn nested_message() {
1✔
155
        let inner = TestMessage::new("today", 100);
1✔
156
        let mut val = TestMessage::new("tomorrow", 50);
1✔
157
        val.set_sub_message(inner);
1✔
158

1✔
159
        let msg_json = val.to_json().unwrap();
1✔
160
        assert_eq!(
1✔
161
            msg_json,
1✔
162
            "{\"key\":\"tomorrow\",\"value\":50,\"sub_message\":{\"key\":\"today\",\"value\":100,\"sub_message\":\
1✔
163
             null}}"
1✔
164
        );
1✔
165

166
        let msg_base64 = val.to_base64().unwrap();
1✔
167
        assert_eq!(
1✔
168
            msg_base64,
1✔
169
            "CAAAAAAAAAB0b21vcnJvdzIAAAAAAAAAAQUAAAAAAAAAdG9kYXlkAAAAAAAAAAA="
1✔
170
        );
1✔
171

172
        let msg_bin = val.to_binary().unwrap();
1✔
173
        assert_eq!(
1✔
174
            msg_bin,
1✔
175
            b"\x08\x00\x00\x00\x00\x00\x00\x00\x74\x6f\x6d\x6f\x72\x72\x6f\x77\x32\x00\x00\x00\x00\x00\x00\x00\x01\x05\x00\x00\x00\x00\x00\x00\x00\x74\x6f\x64\x61\x79\x64\x00\x00\x00\x00\x00\x00\x00\x00".to_vec()
1✔
176
        );
1✔
177

178
        let val2 = TestMessage::from_json(&msg_json).unwrap();
1✔
179
        assert_eq!(val, val2);
1✔
180

181
        let val2 = TestMessage::from_base64(&msg_base64).unwrap();
1✔
182
        assert_eq!(val, val2);
1✔
183

184
        let val2 = TestMessage::from_binary(&msg_bin).unwrap();
1✔
185
        assert_eq!(val, val2);
1✔
186
    }
1✔
187

188
    #[test]
1✔
189
    fn fail_json() {
1✔
190
        let err = TestMessage::from_json("{\"key\":5}").unwrap_err();
1✔
191
        assert!(matches!(err, MessageFormatError::JSONError {}));
1✔
192
    }
1✔
193

194
    #[test]
1✔
195
    fn fail_base64() {
1✔
196
        let err = TestMessage::from_base64("aaaaa$aaaaa").unwrap_err();
1✔
197
        assert!(matches!(err, MessageFormatError::Base64DeserializeError {}));
1✔
198

199
        let err = TestMessage::from_base64("j6h0b21vcnJvdzKTpXRvZGF5ZMA=").unwrap_err();
1✔
200
        assert!(matches!(err, MessageFormatError::BinaryDeserializeError {}));
1✔
201
    }
1✔
202

203
    #[test]
1✔
204
    fn fail_binary() {
1✔
205
        let err = TestMessage::from_binary(b"").unwrap_err();
1✔
206
        assert!(matches!(err, MessageFormatError::BinaryDeserializeError {}));
1✔
207
    }
1✔
208
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc