Skip to content

Commit 2e0bbdf

Browse files
committed
quicklog(serialize): impl Serialize for primitives, &str
1 parent 4478245 commit 2e0bbdf

File tree

3 files changed

+145
-31
lines changed

3 files changed

+145
-31
lines changed

quicklog/examples/macros.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use quicklog::{
22
debug, error, flush_all, info, init,
3-
serialize::{encode_i32, Serialize, Store},
3+
serialize::{Serialize, Store},
44
trace, warn, with_flush, with_formatter, LogRecord, PatternFormatter,
55
};
66
use quicklog_flush::stdout_flusher::StdoutFlusher;
@@ -18,7 +18,7 @@ impl std::fmt::Display for S {
1818

1919
impl Serialize for S {
2020
fn encode<'buf>(&self, write_buf: &'buf mut [u8]) -> Store<'buf> {
21-
encode_i32(self.i, write_buf)
21+
self.i.encode(write_buf)
2222
}
2323

2424
fn buffer_size_required(&self) -> usize {

quicklog/src/serialize/mod.rs

+124-27
Original file line numberDiff line numberDiff line change
@@ -37,50 +37,147 @@ impl Display for Store<'_> {
3737
}
3838
}
3939

40-
macro_rules! gen_encode_decode {
41-
($name:ident, $primitive:ty) => {
42-
pub fn $name(val: $primitive, write_buf: &mut [u8]) -> Store {
43-
assert!(std::mem::size_of::<$primitive>() == write_buf.len());
44-
45-
fn decode(read_buf: &[u8]) -> String {
46-
let x = <$primitive>::from_le_bytes(read_buf.try_into().unwrap());
47-
format!("{}", x)
40+
macro_rules! gen_serialize {
41+
($primitive:ty) => {
42+
impl Serialize for $primitive {
43+
fn encode<'buf>(&self, write_buf: &'buf mut [u8]) -> Store<'buf> {
44+
assert!(std::mem::size_of::<$primitive>() == write_buf.len());
45+
fn decode(read_buf: &[u8]) -> String {
46+
let x = <$primitive>::from_le_bytes(read_buf.try_into().unwrap());
47+
format!("{}", x)
48+
}
49+
50+
let size = std::mem::size_of::<$primitive>();
51+
let (x, _) = write_buf.split_at_mut(size);
52+
x.copy_from_slice(&self.to_le_bytes());
53+
Store::new(decode, &*x)
4854
}
4955

50-
let size = std::mem::size_of::<$primitive>();
51-
let (x, _) = write_buf.split_at_mut(size);
52-
x.copy_from_slice(&val.to_le_bytes());
53-
Store::new(decode, x)
56+
fn buffer_size_required(&self) -> usize {
57+
std::mem::size_of::<$primitive>()
58+
}
5459
}
5560
};
5661
}
5762

58-
gen_encode_decode!(encode_i32, i32);
59-
gen_encode_decode!(encode_i64, i64);
60-
gen_encode_decode!(encode_f32, f32);
61-
gen_encode_decode!(encode_f64, f64);
62-
gen_encode_decode!(encode_usize, usize);
63+
gen_serialize!(i32);
64+
gen_serialize!(i64);
65+
gen_serialize!(isize);
66+
gen_serialize!(f32);
67+
gen_serialize!(f64);
68+
gen_serialize!(u32);
69+
gen_serialize!(u64);
70+
gen_serialize!(usize);
6371

64-
pub fn encode_str<'buf>(val: &str, write_buf: &'buf mut [u8]) -> Store<'buf> {
65-
assert!(val.len() == write_buf.len());
66-
fn decode(read_buf: &[u8]) -> String {
67-
let x = from_utf8(read_buf).unwrap();
68-
x.to_string()
72+
impl Serialize for &str {
73+
fn encode<'buf>(&self, write_buf: &'buf mut [u8]) -> Store<'buf> {
74+
assert!(self.len() == write_buf.len());
75+
fn decode(read_buf: &[u8]) -> String {
76+
let x = from_utf8(read_buf).unwrap();
77+
x.to_string()
78+
}
79+
write_buf.copy_from_slice(self.as_bytes());
80+
Store::new(decode, write_buf)
81+
}
82+
83+
fn buffer_size_required(&self) -> usize {
84+
self.len()
6985
}
70-
write_buf.copy_from_slice(val.as_bytes());
71-
Store::new(decode, write_buf)
7286
}
7387

7488
/// Eager evaluation into a String for debug structs
7589
pub fn encode_debug<T: std::fmt::Debug>(val: T, write_buf: &mut [u8]) -> Store {
7690
let val_string = format!("{:?}", val);
77-
assert!(val_string.len() == write_buf.len());
91+
// TODO: change back to strict equality when Serialize implemented, to use
92+
// `buffer_size_required`
93+
assert!(val_string.len() <= write_buf.len());
7894

7995
fn decode(read_buf: &[u8]) -> String {
8096
let x = from_utf8(read_buf).unwrap();
8197
x.to_string()
8298
}
8399

84-
write_buf.copy_from_slice(val_string.as_bytes());
85-
Store::new(decode, write_buf)
100+
let (chunk, _) = write_buf.split_at_mut(val_string.len());
101+
chunk.copy_from_slice(val_string.as_bytes());
102+
Store::new(decode, chunk)
103+
}
104+
105+
#[cfg(test)]
106+
mod tests {
107+
use crate::serialize::encode_debug;
108+
109+
use super::Serialize;
110+
111+
macro_rules! assert_primitive_encode_decode {
112+
($primitive:ty, $val:expr) => {{
113+
const BUF_SIZE: usize = std::mem::size_of::<$primitive>();
114+
let mut buf = [0u8; BUF_SIZE];
115+
116+
let x: $primitive = $val;
117+
let x_store = x.encode(&mut buf);
118+
assert_eq!(format!("{}", x), (x_store.decode_fn)(&buf));
119+
}};
120+
}
121+
122+
#[test]
123+
fn serialize_primitives() {
124+
assert_primitive_encode_decode!(i32, -1);
125+
assert_primitive_encode_decode!(i64, -123);
126+
assert_primitive_encode_decode!(isize, -1234);
127+
assert_primitive_encode_decode!(f32, 1.23);
128+
assert_primitive_encode_decode!(f64, 1.23456);
129+
assert_primitive_encode_decode!(u32, 999);
130+
assert_primitive_encode_decode!(u64, 9999);
131+
assert_primitive_encode_decode!(usize, 99999);
132+
}
133+
134+
#[test]
135+
fn serialize_multiple_primitives() {
136+
let mut buf = [0; 128];
137+
let a: i32 = -1;
138+
let b: u32 = 999;
139+
let c: usize = 100000;
140+
141+
let (a_chunk, chunk) = buf.split_at_mut(a.buffer_size_required());
142+
let (b_chunk, chunk) = chunk.split_at_mut(b.buffer_size_required());
143+
let (c_chunk, _) = chunk.split_at_mut(c.buffer_size_required());
144+
145+
let a_store = a.encode(a_chunk);
146+
let b_store = b.encode(b_chunk);
147+
let c_store = c.encode(c_chunk);
148+
149+
let a_str = (a_store.decode_fn)(a_store.buffer);
150+
let b_str = (b_store.decode_fn)(b_store.buffer);
151+
let c_str = (c_store.decode_fn)(c_store.buffer);
152+
153+
assert_eq!(
154+
format!("{} {} {}", a, b, c),
155+
format!("{} {} {}", a_str, b_str, c_str)
156+
)
157+
}
158+
159+
#[test]
160+
fn serialize_str() {
161+
let mut buf = [0; 128];
162+
let s = "hello world";
163+
let (s_chunk, _) = buf.split_at_mut(s.buffer_size_required());
164+
let store = s.encode(s_chunk);
165+
166+
assert_eq!(s, format!("{}", store).as_str())
167+
}
168+
169+
#[test]
170+
fn serialize_debug() {
171+
#[derive(Debug)]
172+
#[allow(unused)]
173+
struct DebugStruct {
174+
s: &'static str,
175+
}
176+
177+
let mut buf = [0; 128];
178+
let s = DebugStruct { s: "Hello World" };
179+
let store = encode_debug(&s, &mut buf);
180+
181+
assert_eq!(format!("{:?}", s), format!("{}", store))
182+
}
86183
}

quicklog/tests/failures/struct_missing_display.stderr

+19-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,15 @@ error[E0277]: the trait bound `Something: Serialize` is not satisfied
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Serialize` is not implemented for `Something`
66
|
77
= help: the following other types implement trait `Serialize`:
8-
SerializeStruct
9-
BigStruct
8+
isize
9+
i32
10+
i64
11+
usize
12+
u32
13+
u64
14+
f32
15+
f64
16+
and $N others
1017
note: required by a bound in `serialize_check`
1118
--> tests/failures/struct_missing_display.rs:12:5
1219
|
@@ -31,6 +38,11 @@ error[E0599]: no method named `encode` found for struct `Something` in the curre
3138
= note: the following trait defines an item `encode`, perhaps you need to implement it:
3239
candidate #1: `Serialize`
3340
= note: this error originates in the macro `quicklog::make_store` which comes from the expansion of the macro `info` (in Nightly builds, run with -Z macro-backtrace for more info)
41+
help: one of the expressions' fields has a method of the same name
42+
--> src/macros.rs
43+
|
44+
| .some_str.encode($crate::logger().get_chunk_as_mut($serializable.buffer_size_required()))
45+
| +++++++++
3446

3547
error[E0599]: no method named `buffer_size_required` found for struct `Something` in the current scope
3648
--> tests/failures/struct_missing_display.rs:12:5
@@ -47,3 +59,8 @@ error[E0599]: no method named `buffer_size_required` found for struct `Something
4759
= note: the following trait defines an item `buffer_size_required`, perhaps you need to implement it:
4860
candidate #1: `Serialize`
4961
= note: this error originates in the macro `quicklog::make_store` which comes from the expansion of the macro `info` (in Nightly builds, run with -Z macro-backtrace for more info)
62+
help: one of the expressions' fields has a method of the same name
63+
--> src/macros.rs
64+
|
65+
| .encode($crate::logger().get_chunk_as_mut($serializable.some_str.buffer_size_required()))
66+
| +++++++++

0 commit comments

Comments
 (0)