1use crate::transport::Transport;
4use airbender_codec::{AirbenderCodecV0, CodecError};
5use airbender_core::wire::FramedReader;
6use core::fmt;
7
8#[derive(Debug)]
10pub enum GuestError {
11 Codec(CodecError),
12 UnsupportedTarget,
13}
14
15impl From<CodecError> for GuestError {
16 fn from(err: CodecError) -> Self {
17 GuestError::Codec(err)
18 }
19}
20
21impl fmt::Display for GuestError {
22 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 match self {
24 GuestError::Codec(err) => write!(f, "{err}"),
25 GuestError::UnsupportedTarget => {
26 f.write_str("csr transport is only available on riscv32")
27 }
28 }
29 }
30}
31
32pub fn read<T: serde::de::DeserializeOwned>() -> Result<T, GuestError> {
34 #[cfg(target_arch = "riscv32")]
35 {
36 let mut transport = crate::transport::CsrTransport;
37 read_with(&mut transport)
38 }
39 #[cfg(not(target_arch = "riscv32"))]
40 {
41 Err(GuestError::UnsupportedTarget)
42 }
43}
44
45pub fn read_with<T: serde::de::DeserializeOwned>(
60 transport: &mut impl Transport,
61) -> Result<T, GuestError> {
62 let mut reader = FramedReader::new(|| transport.read_word());
63 let result = AirbenderCodecV0::decode_from_reader(&mut reader);
64 reader.discard_rest_of_frame();
67 let value = result.map_err(GuestError::Codec)?;
68 let remaining = reader.remaining();
69 if remaining != 0 {
70 let expected = reader.payload_len();
71 return Err(GuestError::Codec(CodecError::TrailingBytes {
72 expected,
73 read: expected - remaining,
74 }));
75 }
76 Ok(value)
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82 use crate::transport::MockTransport;
83 use airbender_codec::AirbenderCodec; use airbender_core::wire::frame_words_from_bytes;
85 use alloc::vec;
86
87 #[derive(Debug, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
88 struct Payload {
89 counter: u32,
90 bytes: alloc::vec::Vec<u8>,
91 }
92
93 #[test]
94 fn reads_value_from_transport() {
95 let payload = Payload {
96 counter: 7,
97 bytes: vec![10u8, 20, 30],
98 };
99 let encoded = AirbenderCodecV0::encode(&payload).expect("encode");
100 let words = frame_words_from_bytes(&encoded).expect("frame words");
101 let mut transport = MockTransport::new(words);
102 let decoded: Payload = read_with(&mut transport).expect("read");
103 assert_eq!(decoded, payload);
104 }
105
106 #[test]
107 fn reads_large_multiword_payload() {
108 let payload = Payload {
111 counter: u32::MAX,
112 bytes: (0..10_000u32).map(|i| (i * 31 + 7) as u8).collect(),
113 };
114 let encoded = AirbenderCodecV0::encode(&payload).expect("encode");
115 let words = frame_words_from_bytes(&encoded).expect("frame words");
116 let mut transport = MockTransport::new(words);
117 let decoded: Payload = read_with(&mut transport).expect("read");
118 assert_eq!(decoded, payload);
119 }
120
121 #[test]
122 fn rejects_trailing_bytes_like_the_buffered_codec() {
123 let payload = Payload {
126 counter: 1,
127 bytes: vec![9u8],
128 };
129 let mut encoded = AirbenderCodecV0::encode(&payload).expect("encode");
130 encoded.extend_from_slice(&[0u8; 5]); let words = frame_words_from_bytes(&encoded).expect("frame words");
132 let mut transport = MockTransport::new(words);
133 let err = read_with::<Payload>(&mut transport).expect_err("must reject trailing bytes");
134 assert!(matches!(
135 err,
136 GuestError::Codec(CodecError::TrailingBytes { .. })
137 ));
138 }
139
140 #[test]
141 fn rejected_frame_does_not_desync_the_next_frame() {
142 let bad = Payload {
145 counter: 1,
146 bytes: vec![9u8, 8, 7],
147 };
148 let good = Payload {
149 counter: 42,
150 bytes: vec![1u8, 2, 3, 4, 5],
151 };
152
153 let mut bad_encoded = AirbenderCodecV0::encode(&bad).expect("encode");
154 bad_encoded.extend_from_slice(&[0u8; 6]); let good_encoded = AirbenderCodecV0::encode(&good).expect("encode");
156
157 let mut words = frame_words_from_bytes(&bad_encoded).expect("frame bad");
158 words.extend(frame_words_from_bytes(&good_encoded).expect("frame good"));
159 let mut transport = MockTransport::new(words);
160
161 let err = read_with::<Payload>(&mut transport).expect_err("first frame rejected");
162 assert!(matches!(
163 err,
164 GuestError::Codec(CodecError::TrailingBytes { .. })
165 ));
166 let decoded: Payload = read_with(&mut transport).expect("second frame decodes");
168 assert_eq!(decoded, good);
169 }
170
171 #[test]
172 fn mid_decode_failure_does_not_desync_the_next_frame() {
173 #[derive(Debug, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
178 struct HasBool {
179 flag: bool,
180 rest: u32,
181 }
182
183 let bad_frame_bytes = [2u8, 0, 0, 0, 0, 0, 0, 0];
186 let good = Payload {
187 counter: 99,
188 bytes: vec![7u8, 7, 7],
189 };
190 let good_encoded = AirbenderCodecV0::encode(&good).expect("encode");
191
192 let mut words = frame_words_from_bytes(&bad_frame_bytes).expect("frame bad");
193 words.extend(frame_words_from_bytes(&good_encoded).expect("frame good"));
194 let mut transport = MockTransport::new(words);
195
196 let err = read_with::<HasBool>(&mut transport).expect_err("decode must fail");
197 assert!(matches!(err, GuestError::Codec(CodecError::Decode(_))));
198 let decoded: Payload = read_with(&mut transport).expect("second frame decodes");
199 assert_eq!(decoded, good);
200 }
201}