Skip to content

Commit 6bf4ddd

Browse files
committed
use bytes crate instead of Vec<u8>
1 parent 14548da commit 6bf4ddd

13 files changed

Lines changed: 95 additions & 84 deletions

File tree

AGENTS.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,17 @@ fn should_return_error_when_key_not_found() {
5858
}
5959
```
6060

61+
### Encoding and Serialization
62+
63+
- Prefer `bytes::Bytes` and `bytes::BytesMut` over `Vec<u8>` for byte buffers
64+
- Use `Bytes` for immutable byte slices (return types, function parameters)
65+
- Use `BytesMut` for mutable byte buffers during encoding
66+
- The `bytes` crate is available as a workspace dependency
67+
6168
### Dependencies
6269

6370
- **slatedb**: The underlying storage engine for all database implementations
71+
- **bytes**: Byte buffer types (`Bytes`, `BytesMut`) for efficient zero-copy operations
6472
- Workspace dependencies are defined in the root `Cargo.toml`
6573
- Prefer adding dependencies at the workspace level when shared across crates
6674

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,5 @@ edition = "2024"
1313
[workspace.dependencies]
1414
slatedb = "0.9.1"
1515
opendata-common = { path = "./opendata-common" }
16+
rstest = "0.19"
17+
bytes = "1.0"

open-tsdb/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ edition.workspace = true
66
[dependencies]
77
slatedb.workspace = true
88
opendata-common.workspace = true
9+
bytes.workspace = true
910
roaring = "0.7"
1011
tsz = "0.1"
1112

1213
[dev-dependencies]
13-
rstest = "0.19"
14+
rstest.workspace = true

open-tsdb/src/serde/bucket_list.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// BucketList value structure
22

33
use super::common::*;
4+
use bytes::{Bytes, BytesMut};
45

56
/// BucketList value: SingleArray<(bucket_size: u8, time_bucket: u32)>
67
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -9,10 +10,10 @@ pub struct BucketListValue {
910
}
1011

1112
impl BucketListValue {
12-
pub fn encode(&self) -> Vec<u8> {
13-
let mut buf = Vec::new();
13+
pub fn encode(&self) -> Bytes {
14+
let mut buf = BytesMut::new();
1415
encode_single_array(&self.buckets, &mut buf);
15-
buf
16+
buf.freeze()
1617
}
1718

1819
pub fn decode(buf: &[u8], count: usize) -> Result<Self, EncodingError> {
@@ -23,8 +24,8 @@ impl BucketListValue {
2324
}
2425

2526
impl Encode for (TimeBucketSize, TimeBucket) {
26-
fn encode(&self, buf: &mut Vec<u8>) {
27-
buf.push(self.0);
27+
fn encode(&self, buf: &mut BytesMut) {
28+
buf.extend_from_slice(&[self.0]);
2829
buf.extend_from_slice(&self.1.to_le_bytes());
2930
}
3031
}
@@ -57,7 +58,7 @@ mod tests {
5758

5859
// when
5960
let encoded = value.encode();
60-
let decoded = BucketListValue::decode(&encoded, 3).unwrap();
61+
let decoded = BucketListValue::decode(encoded.as_ref(), 3).unwrap();
6162

6263
// then
6364
assert_eq!(decoded, value);
@@ -70,7 +71,7 @@ mod tests {
7071

7172
// when
7273
let encoded = value.encode();
73-
let decoded = BucketListValue::decode(&encoded, 0).unwrap();
74+
let decoded = BucketListValue::decode(encoded.as_ref(), 0).unwrap();
7475

7576
// then
7677
assert_eq!(decoded, value);

open-tsdb/src/serde/common.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// Common types, constants, error handling, record tag encoding, and common encoding utilities
22

3+
use bytes::BytesMut;
4+
35
/// Key format version (currently 0x01)
46
pub const KEY_VERSION: u8 = 0x01;
57

@@ -87,7 +89,7 @@ pub fn decode_record_tag(tag: u8) -> Result<(RecordType, Option<TimeBucketSize>)
8789
/// Encode a UTF-8 string
8890
///
8991
/// Format: `len: u16` (little-endian) + `len` bytes of UTF-8
90-
pub fn encode_utf8(s: &str, buf: &mut Vec<u8>) {
92+
pub fn encode_utf8(s: &str, buf: &mut BytesMut) {
9193
let bytes = s.as_bytes();
9294
let len = bytes.len();
9395
if len > u16::MAX as usize {
@@ -130,7 +132,7 @@ pub fn decode_utf8(buf: &mut &[u8]) -> Result<String, EncodingError> {
130132
/// Encode an optional non-empty UTF-8 string
131133
///
132134
/// Format: Same as Utf8, but `len = 0` means `None`
133-
pub fn encode_optional_utf8(opt: Option<&str>, buf: &mut Vec<u8>) {
135+
pub fn encode_optional_utf8(opt: Option<&str>, buf: &mut BytesMut) {
134136
match opt {
135137
Some(s) => encode_utf8(s, buf),
136138
None => {
@@ -158,7 +160,7 @@ pub fn decode_optional_utf8(buf: &mut &[u8]) -> Result<Option<String>, EncodingE
158160

159161
/// Trait for types that can be encoded to bytes
160162
pub trait Encode {
161-
fn encode(&self, buf: &mut Vec<u8>);
163+
fn encode(&self, buf: &mut BytesMut);
162164
}
163165

164166
/// Trait for types that can be decoded from bytes
@@ -169,7 +171,7 @@ pub trait Decode: Sized {
169171
/// Encode an array of encodable items
170172
///
171173
/// Format: `count: u16` (little-endian) + `count` serialized elements
172-
pub fn encode_array<T: Encode>(items: &[T], buf: &mut Vec<u8>) {
174+
pub fn encode_array<T: Encode>(items: &[T], buf: &mut BytesMut) {
173175
let count = items.len();
174176
if count > u16::MAX as usize {
175177
panic!("Array too long: {} items", count);
@@ -202,7 +204,7 @@ pub fn decode_array<T: Decode>(buf: &mut &[u8]) -> Result<Vec<T>, EncodingError>
202204
/// Encode a single array (no count prefix)
203205
///
204206
/// Format: Serialized elements back-to-back with no additional padding
205-
pub fn encode_single_array<T: Encode>(items: &[T], buf: &mut Vec<u8>) {
207+
pub fn encode_single_array<T: Encode>(items: &[T], buf: &mut BytesMut) {
206208
for item in items {
207209
item.encode(buf);
208210
}
@@ -269,11 +271,11 @@ mod tests {
269271
fn should_encode_and_decode_utf8() {
270272
// given
271273
let s = "Hello, 世界!";
272-
let mut buf = Vec::new();
274+
let mut buf = BytesMut::new();
273275

274276
// when
275277
encode_utf8(s, &mut buf);
276-
let mut slice = buf.as_slice();
278+
let mut slice = buf.as_ref();
277279
let decoded = decode_utf8(&mut slice).unwrap();
278280

279281
// then
@@ -285,11 +287,11 @@ mod tests {
285287
fn should_encode_and_decode_optional_utf8_some() {
286288
// given
287289
let s = Some("test");
288-
let mut buf = Vec::new();
290+
let mut buf = BytesMut::new();
289291

290292
// when
291293
encode_optional_utf8(s, &mut buf);
292-
let mut slice = buf.as_slice();
294+
let mut slice = buf.as_ref();
293295
let decoded = decode_optional_utf8(&mut slice).unwrap();
294296

295297
// then
@@ -300,11 +302,11 @@ mod tests {
300302
fn should_encode_and_decode_optional_utf8_none() {
301303
// given
302304
let s: Option<&str> = None;
303-
let mut buf = Vec::new();
305+
let mut buf = BytesMut::new();
304306

305307
// when
306308
encode_optional_utf8(s, &mut buf);
307-
let mut slice = buf.as_slice();
309+
let mut slice = buf.as_ref();
308310
let decoded = decode_optional_utf8(&mut slice).unwrap();
309311

310312
// then

open-tsdb/src/serde/dictionary.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// SeriesDictionary value structure
22

33
use super::common::*;
4+
use bytes::{Bytes, BytesMut};
45

56
/// SeriesDictionary value: SingleArray<series_id: u32>
67
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -9,10 +10,10 @@ pub struct SeriesDictionaryValue {
910
}
1011

1112
impl SeriesDictionaryValue {
12-
pub fn encode(&self) -> Vec<u8> {
13-
let mut buf = Vec::new();
13+
pub fn encode(&self) -> Bytes {
14+
let mut buf = BytesMut::new();
1415
encode_single_array(&self.series_ids, &mut buf);
15-
buf
16+
buf.freeze()
1617
}
1718

1819
pub fn decode(buf: &[u8], count: u8) -> Result<Self, EncodingError> {
@@ -23,7 +24,7 @@ impl SeriesDictionaryValue {
2324
}
2425

2526
impl Encode for SeriesId {
26-
fn encode(&self, buf: &mut Vec<u8>) {
27+
fn encode(&self, buf: &mut BytesMut) {
2728
buf.extend_from_slice(&self.to_le_bytes());
2829
}
2930
}
@@ -54,7 +55,7 @@ mod tests {
5455

5556
// when
5657
let encoded = value.encode();
57-
let decoded = SeriesDictionaryValue::decode(&encoded, 5u8).unwrap();
58+
let decoded = SeriesDictionaryValue::decode(encoded.as_ref(), 5u8).unwrap();
5859

5960
// then
6061
assert_eq!(decoded, value);
@@ -67,7 +68,7 @@ mod tests {
6768

6869
// when
6970
let encoded = value.encode();
70-
let decoded = SeriesDictionaryValue::decode(&encoded, 0u8).unwrap();
71+
let decoded = SeriesDictionaryValue::decode(encoded.as_ref(), 0u8).unwrap();
7172

7273
// then
7374
assert_eq!(decoded, value);
@@ -82,7 +83,7 @@ mod tests {
8283

8384
// when
8485
let encoded = value.encode();
85-
let decoded = SeriesDictionaryValue::decode(&encoded, 1u8).unwrap();
86+
let decoded = SeriesDictionaryValue::decode(encoded.as_ref(), 1u8).unwrap();
8687

8788
// then
8889
assert_eq!(decoded, value);

open-tsdb/src/serde/forward_index.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// ForwardIndex value structure with MetricMeta and AttributeBinding
22

33
use super::common::*;
4+
use bytes::{Bytes, BytesMut};
45

56
/// MetricMeta: Encodes the series' metric type and auxiliary flags
67
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -24,9 +25,8 @@ impl MetricMeta {
2425
}
2526

2627
impl Encode for MetricMeta {
27-
fn encode(&self, buf: &mut Vec<u8>) {
28-
buf.push(self.metric_type);
29-
buf.push(self.flags);
28+
fn encode(&self, buf: &mut BytesMut) {
29+
buf.extend_from_slice(&[self.metric_type, self.flags]);
3030
}
3131
}
3232

@@ -52,7 +52,7 @@ pub struct AttributeBinding {
5252
}
5353

5454
impl Encode for AttributeBinding {
55-
fn encode(&self, buf: &mut Vec<u8>) {
55+
fn encode(&self, buf: &mut BytesMut) {
5656
encode_utf8(&self.attr, buf);
5757
encode_utf8(&self.value, buf);
5858
}
@@ -76,13 +76,13 @@ pub struct ForwardIndexValue {
7676
}
7777

7878
impl ForwardIndexValue {
79-
pub fn encode(&self) -> Vec<u8> {
80-
let mut buf = Vec::new();
79+
pub fn encode(&self) -> Bytes {
80+
let mut buf = BytesMut::new();
8181
encode_optional_utf8(self.metric_unit.as_deref(), &mut buf);
8282
self.metric_meta.encode(&mut buf);
8383
buf.extend_from_slice(&self.attr_count.to_le_bytes());
8484
encode_array(&self.attrs, &mut buf);
85-
buf
85+
buf.freeze()
8686
}
8787

8888
pub fn decode(buf: &[u8]) -> Result<Self, EncodingError> {
@@ -147,7 +147,7 @@ mod tests {
147147

148148
// when
149149
let encoded = value.encode();
150-
let decoded = ForwardIndexValue::decode(&encoded).unwrap();
150+
let decoded = ForwardIndexValue::decode(encoded.as_ref()).unwrap();
151151

152152
// then
153153
assert_eq!(decoded, value);
@@ -171,7 +171,7 @@ mod tests {
171171

172172
// when
173173
let encoded = value.encode();
174-
let decoded = ForwardIndexValue::decode(&encoded).unwrap();
174+
let decoded = ForwardIndexValue::decode(encoded.as_ref()).unwrap();
175175

176176
// then
177177
assert_eq!(decoded, value);
@@ -194,7 +194,7 @@ mod tests {
194194

195195
// when
196196
let encoded = value.encode();
197-
let decoded = ForwardIndexValue::decode(&encoded).unwrap();
197+
let decoded = ForwardIndexValue::decode(encoded.as_ref()).unwrap();
198198

199199
// then
200200
assert_eq!(decoded, value);

open-tsdb/src/serde/inverted_index.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// InvertedIndex value structure using RoaringBitmap
22

33
use super::common::*;
4+
use bytes::Bytes;
45
use roaring::RoaringBitmap;
56

67
/// InvertedIndex value: RoaringBitmap<u32> encoding series IDs
@@ -10,14 +11,14 @@ pub struct InvertedIndexValue {
1011
}
1112

1213
impl InvertedIndexValue {
13-
pub fn encode(&self) -> Result<Vec<u8>, EncodingError> {
14+
pub fn encode(&self) -> Result<Bytes, EncodingError> {
1415
let mut buf = Vec::new();
1516
self.series_ids
1617
.serialize_into(&mut buf)
1718
.map_err(|e| EncodingError {
1819
message: format!("Failed to serialize RoaringBitmap: {}", e),
1920
})?;
20-
Ok(buf)
21+
Ok(Bytes::from(buf))
2122
}
2223

2324
pub fn decode(buf: &[u8]) -> Result<Self, EncodingError> {
@@ -43,7 +44,7 @@ mod tests {
4344

4445
// when
4546
let encoded = value.encode().unwrap();
46-
let decoded = InvertedIndexValue::decode(&encoded).unwrap();
47+
let decoded = InvertedIndexValue::decode(encoded.as_ref()).unwrap();
4748

4849
// then
4950
assert_eq!(decoded.series_ids, value.series_ids);
@@ -58,7 +59,7 @@ mod tests {
5859

5960
// when
6061
let encoded = value.encode().unwrap();
61-
let decoded = InvertedIndexValue::decode(&encoded).unwrap();
62+
let decoded = InvertedIndexValue::decode(encoded.as_ref()).unwrap();
6263

6364
// then
6465
assert_eq!(decoded.series_ids, value.series_ids);
@@ -76,7 +77,7 @@ mod tests {
7677

7778
// when
7879
let encoded = value.encode().unwrap();
79-
let decoded = InvertedIndexValue::decode(&encoded).unwrap();
80+
let decoded = InvertedIndexValue::decode(encoded.as_ref()).unwrap();
8081

8182
// then
8283
assert_eq!(decoded.series_ids, value.series_ids);

0 commit comments

Comments
 (0)