Skip to main content

reifydb_core/util/encoding/keycode/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4// This file includes and modifies code from the toydb project (https://github.com/erikgrinaker/toydb),
5// originally licensed under the Apache License, Version 2.0.
6// Original copyright:
7//   Copyright (c) 2024 Erik Grinaker
8//
9// The original Apache License can be found at:
10//   http://www.apache.org/licenses/LICENSE-2.0
11
12//! Order-preserving codec used to turn typed keys into the bytes that go on disk.
13//!
14//! Encoded byte sequences sort lexicographically in the same order as the logical keys they represent, so range scans
15//! over the storage tier produce results in natural key order without any decode pass. Submodules cover the
16//! catalog-specific key encodings, the generic `Serializer` and `Deserializer` pair, and per-type encoders for
17//! booleans, floats, and signed and unsigned integers.
18//!
19//! Invariant: the codec is order-preserving. For any two values `a < b` in their natural ordering, their encoded bytes
20//! must satisfy `encode(a) < encode(b)` lexicographically. Storage range queries, CDC, and replication all rely on this
21//! property; breaking it silently corrupts every range-scan-based operation in the workspace.
22
23use serde::{Deserialize, Serialize};
24
25pub mod catalog;
26pub mod deserialize;
27pub mod deserializer;
28pub mod serialize;
29pub mod serializer;
30pub mod varint;
31
32use std::{f32, f64};
33
34use reifydb_type::{
35	Result,
36	error::{Error, TypeError},
37};
38
39use crate::{
40	encoded::key::EncodedKey,
41	util::encoding::keycode::{deserialize::Deserializer, serialize::Serializer},
42};
43
44pub trait ByteSink {
45	fn push(&mut self, byte: u8);
46	fn extend_from_slice(&mut self, slice: &[u8]);
47}
48
49impl ByteSink for Vec<u8> {
50	fn push(&mut self, byte: u8) {
51		Vec::push(self, byte);
52	}
53	fn extend_from_slice(&mut self, slice: &[u8]) {
54		Vec::extend_from_slice(self, slice);
55	}
56}
57
58impl ByteSink for EncodedKey {
59	fn push(&mut self, byte: u8) {
60		EncodedKey::push(self, byte);
61	}
62	fn extend_from_slice(&mut self, slice: &[u8]) {
63		EncodedKey::extend_from_slice(self, slice);
64	}
65}
66
67pub fn encode_bool(value: bool) -> u8 {
68	if value {
69		0x00
70	} else {
71		0x01
72	}
73}
74
75pub fn encode_f32(value: f32) -> [u8; 4] {
76	let bits = value.to_bits();
77	if value.is_sign_negative() {
78		bits.to_be_bytes()
79	} else {
80		(!(bits ^ 0x80000000)).to_be_bytes()
81	}
82}
83
84pub fn encode_f64(value: f64) -> [u8; 8] {
85	let bits = value.to_bits();
86	if value.is_sign_negative() {
87		bits.to_be_bytes()
88	} else {
89		(!(bits ^ 0x8000000000000000)).to_be_bytes()
90	}
91}
92
93pub fn encode_i8(value: i8) -> [u8; 1] {
94	(!(value as u8 ^ 0x80)).to_be_bytes()
95}
96
97pub fn encode_i16(value: i16) -> [u8; 2] {
98	(!(value as u16 ^ 0x8000)).to_be_bytes()
99}
100
101pub fn encode_i32(value: i32) -> [u8; 4] {
102	(!(value as u32 ^ 0x80000000)).to_be_bytes()
103}
104
105pub fn encode_i64(value: i64) -> [u8; 8] {
106	(!(value as u64 ^ 0x8000000000000000)).to_be_bytes()
107}
108
109pub fn encode_i64_varint<B: ByteSink>(value: i64, output: &mut B) {
110	if value >= 0 {
111		if value < 64 {
112			output.push(!(0x80 | value as u8));
113		} else if value < 8192 + 64 {
114			let v = (value - 64) as u16;
115			output.push(!(0xc0 | (v >> 8) as u8));
116			output.push(!(v as u8));
117		} else {
118			output.push(!0xfe);
119			let inv = !(value as u64);
120			output.extend_from_slice(&inv.to_be_bytes());
121		}
122	} else if value >= -64 {
123		output.push(!(0x40 | (value + 64) as u8));
124	} else if value >= -8192 - 64 {
125		let v = (value + 64 + 8192) as u16;
126		output.push(!(0x20 | (v >> 8) as u8));
127		output.push(!(v as u8));
128	} else {
129		output.push(!0x01);
130		let inv = !(value as u64);
131		output.extend_from_slice(&inv.to_be_bytes());
132	}
133}
134
135pub fn encode_i128(value: i128) -> [u8; 16] {
136	(!(value as u128 ^ 0x80000000000000000000000000000000)).to_be_bytes()
137}
138
139pub fn encode_u8(value: u8) -> u8 {
140	!value
141}
142
143pub fn encode_u16(value: u16) -> [u8; 2] {
144	(!value).to_be_bytes()
145}
146
147pub fn encode_u32(value: u32) -> [u8; 4] {
148	(!value).to_be_bytes()
149}
150
151pub fn encode_u32_varint<B: ByteSink>(value: u32, output: &mut B) {
152	encode_u64_varint(value as u64, output);
153}
154
155pub fn encode_u64(value: u64) -> [u8; 8] {
156	(!value).to_be_bytes()
157}
158
159pub fn encode_u64_varint<B: ByteSink>(value: u64, output: &mut B) {
160	if value < (1 << 7) {
161		output.push(!(value as u8));
162	} else if value < (1 << 14) {
163		output.push(!(0x80 | (value >> 8) as u8));
164		output.push(!(value as u8));
165	} else if value < (1 << 21) {
166		output.push(!(0xc0 | (value >> 16) as u8));
167		output.push(!((value >> 8) as u8));
168		output.push(!(value as u8));
169	} else if value < (1 << 28) {
170		output.push(!(0xe0 | (value >> 24) as u8));
171		output.push(!((value >> 16) as u8));
172		output.push(!((value >> 8) as u8));
173		output.push(!(value as u8));
174	} else if value < (1 << 35) {
175		output.push(!(0xf0 | (value >> 32) as u8));
176		output.push(!((value >> 24) as u8));
177		output.push(!((value >> 16) as u8));
178		output.push(!((value >> 8) as u8));
179		output.push(!(value as u8));
180	} else if value < (1 << 42) {
181		output.push(!(0xf8 | (value >> 40) as u8));
182		output.push(!((value >> 32) as u8));
183		output.push(!((value >> 24) as u8));
184		output.push(!((value >> 16) as u8));
185		output.push(!((value >> 8) as u8));
186		output.push(!(value as u8));
187	} else if value < (1 << 49) {
188		output.push(!(0xfc | (value >> 48) as u8));
189		output.push(!((value >> 40) as u8));
190		output.push(!((value >> 32) as u8));
191		output.push(!((value >> 24) as u8));
192		output.push(!((value >> 16) as u8));
193		output.push(!((value >> 8) as u8));
194		output.push(!(value as u8));
195	} else if value < (1 << 56) {
196		output.push(!(0xfe | (value >> 56) as u8));
197		output.push(!((value >> 48) as u8));
198		output.push(!((value >> 40) as u8));
199		output.push(!((value >> 32) as u8));
200		output.push(!((value >> 24) as u8));
201		output.push(!((value >> 16) as u8));
202		output.push(!((value >> 8) as u8));
203		output.push(!(value as u8));
204	} else {
205		output.push(!0xff);
206		let inv = !value;
207		output.extend_from_slice(&inv.to_be_bytes());
208	}
209}
210
211pub fn decode_i64_varint(input: &mut &[u8]) -> Result<i64> {
212	if input.is_empty() {
213		return Err(Error::from(TypeError::SerdeKeycode {
214			message: "unexpected end of key while decoding i64 varint".to_string(),
215		}));
216	}
217	let first = !input[0];
218	let len = if first >= 0x80 {
219		if first < 0xc0 {
220			1
221		} else if first < 0xfe {
222			2
223		} else {
224			9
225		}
226	} else if first >= 0x40 {
227		1
228	} else if first >= 0x20 {
229		2
230	} else {
231		9
232	};
233
234	if input.len() < len {
235		return Err(Error::from(TypeError::SerdeKeycode {
236			message: "unexpected end of key while decoding i64 varint".to_string(),
237		}));
238	}
239
240	let mut buf = input[..len].to_vec();
241	for b in buf.iter_mut() {
242		*b = !*b;
243	}
244	let mut slice = &buf[..];
245	let v = varint::decode_i64_varint(&mut slice).ok_or_else(|| {
246		Error::from(TypeError::SerdeKeycode {
247			message: "failed to decode signed varint".to_string(),
248		})
249	})?;
250	*input = &input[len..];
251	Ok(v)
252}
253
254pub fn decode_u64_varint(input: &mut &[u8]) -> Result<u64> {
255	if input.is_empty() {
256		return Err(Error::from(TypeError::SerdeKeycode {
257			message: "unexpected end of key while decoding varint".to_string(),
258		}));
259	}
260	let first = !input[0];
261	let prefix = first.leading_ones() as usize;
262	let len = if prefix == 0 {
263		1
264	} else if prefix < 8 {
265		prefix + 1
266	} else {
267		9
268	};
269
270	if input.len() < len {
271		return Err(Error::from(TypeError::SerdeKeycode {
272			message: "unexpected end of key while decoding varint".to_string(),
273		}));
274	}
275
276	let mut buf = input[..len].to_vec();
277	for b in buf.iter_mut() {
278		*b = !*b;
279	}
280	let mut slice = &buf[..];
281	let v = varint::decode_u64_varint(&mut slice).unwrap();
282	*input = &input[len..];
283	Ok(v)
284}
285
286pub fn encode_u128(value: u128) -> [u8; 16] {
287	(!value).to_be_bytes()
288}
289
290pub fn encode_bytes<B: ByteSink>(bytes: &[u8], output: &mut B) {
291	let mut start = 0;
292	while let Some(pos) = bytes[start..].iter().position(|&b| b == 0xff) {
293		let end = start + pos;
294		output.extend_from_slice(&bytes[start..end]);
295		output.extend_from_slice(&[0xff, 0x00]);
296		start = end + 1;
297	}
298	output.extend_from_slice(&bytes[start..]);
299	output.extend_from_slice(&[0xff, 0xff]);
300}
301
302#[macro_export]
303macro_rules! key_prefix {
304    ($($arg:tt)*) => {
305        &EncodedKey::new((&format!($($arg)*)).as_bytes().to_vec())
306    };
307}
308
309pub fn serialize<T: Serialize>(key: &T) -> Vec<u8> {
310	let mut serializer = Serializer {
311		output: Vec::new(),
312	};
313
314	key.serialize(&mut serializer).expect("key must be serializable");
315	serializer.output
316}
317
318pub fn deserialize<'a, T: Deserialize<'a>>(input: &'a [u8]) -> Result<T> {
319	let mut deserializer = Deserializer::from_bytes(input);
320	let t = T::deserialize(&mut deserializer)?;
321	if !deserializer.input.is_empty() {
322		return Err(Error::from(TypeError::SerdeKeycode {
323			message: format!(
324				"unexpected trailing bytes {:x?} at end of key {input:x?}",
325				deserializer.input,
326			),
327		}));
328	}
329	Ok(t)
330}
331
332#[cfg(test)]
333pub mod tests {
334	use std::borrow::Cow;
335
336	const PI_F32: f32 = f32::consts::PI;
337	const PI_F64: f64 = f64::consts::PI;
338
339	use reifydb_type::{
340		util::hex::encode,
341		value::{Value, ordered_f32::OrderedF32, ordered_f64::OrderedF64},
342	};
343	use serde_bytes::ByteBuf;
344
345	use super::*;
346	use crate::util::encoding::keycode::serializer::KeySerializer;
347
348	#[derive(Debug, Deserialize, Serialize, PartialEq)]
349	enum Key<'a> {
350		Unit,
351		NewType(String),
352		Tuple(bool, #[serde(with = "serde_bytes")] Vec<u8>, u64),
353		Cow(
354			#[serde(with = "serde_bytes")]
355			#[serde(borrow)]
356			Cow<'a, [u8]>,
357			bool,
358			#[serde(borrow)] Cow<'a, str>,
359		),
360	}
361
362	macro_rules! test_serde {
363        ( $( $name:ident: $input:expr => $expect:literal, )* ) => {
364        $(
365            #[test]
366            fn $name(){
367                let mut input = $input;
368                let expect = $expect;
369                let output = serialize(&input);
370                assert_eq!(encode(&output), expect, "encode failed");
371
372                let expect = input;
373                input = deserialize(&output).unwrap();
374                assert_eq!(input, expect, "decode failed");
375            }
376        )*
377        };
378    }
379
380	test_serde! {
381	bool_false: false => "01",
382	bool_true: true => "00",
383
384	f32_min: f32::MIN => "ff7fffff",
385	f32_neg_inf: f32::NEG_INFINITY => "ff800000",
386	f32_neg_pi: -PI_F32 => "c0490fdb",
387	f32_neg_zero: -0f32 => "80000000",
388	f32_zero: 0f32 => "7fffffff",
389	f32_pi: PI_F32 => "3fb6f024",
390	f32_max: f32::MAX => "00800000",
391	f32_inf: f32::INFINITY => "007fffff",
392
393	f64_min: f64::MIN => "ffefffffffffffff",
394	f64_neg_inf: f64::NEG_INFINITY => "fff0000000000000",
395	f64_neg_pi: -PI_F64 => "c00921fb54442d18",
396	f64_neg_zero: -0f64 => "8000000000000000",
397	f64_zero: 0f64 => "7fffffffffffffff",
398	f64_pi: PI_F64 => "3ff6de04abbbd2e7",
399	f64_max: f64::MAX => "0010000000000000",
400	f64_inf: f64::INFINITY => "000fffffffffffff",
401
402	i8_min: i8::MIN => "ff",
403	i8_neg_1: -1i8 => "80",
404	i8_0: 0i8 => "7f",
405	i8_1: 1i8 => "7e",
406	i8_max: i8::MAX => "00",
407
408	i16_min: i16::MIN => "ffff",
409	i16_neg_1: -1i16 => "8000",
410	i16_0: 0i16 => "7fff",
411	i16_1: 1i16 => "7ffe",
412	i16_max: i16::MAX => "0000",
413
414	i32_min: i32::MIN => "ffffffff",
415	i32_neg_1: -1i32 => "80000000",
416	i32_0: 0i32 => "7fffffff",
417	i32_1: 1i32 => "7ffffffe",
418	i32_max: i32::MAX => "00000000",
419
420	i64_min: i64::MIN => "fe7fffffffffffffff",
421	i64_neg_65535: -65535i64 => "fe000000000000fffe",
422	i64_neg_1: -1i64 => "80",
423	i64_0: 0i64 => "7f",
424	i64_1: 1i64 => "7e",
425	i64_65535: 65535i64 => "01ffffffffffff0000",
426	i64_max: i64::MAX => "018000000000000000",
427
428	i128_min: i128::MIN => "ffffffffffffffffffffffffffffffff",
429	i128_neg_1: -1i128 => "80000000000000000000000000000000",
430	i128_0: 0i128 => "7fffffffffffffffffffffffffffffff",
431	i128_1: 1i128 => "7ffffffffffffffffffffffffffffffe",
432	i128_max: i128::MAX => "00000000000000000000000000000000",
433
434	u8_min: u8::MIN => "ff",
435	u8_1: 1_u8 => "fe",
436	u8_255: 255_u8 => "00",
437
438	u16_min: u16::MIN => "ffff",
439	u16_1: 1_u16 => "fffe",
440	u16_255: 255_u16 => "ff00",
441	u16_65535: u16::MAX => "0000",
442
443	u32_min: u32::MIN => "ff",
444	u32_1: 1_u32 => "fe",
445	u32_65535: 65535_u32 => "3f0000",
446	u32_max: u32::MAX => "0f00000000",
447
448	u64_min: u64::MIN => "ff",
449	u64_1: 1_u64 => "fe",
450	u64_65535: 65535_u64 => "3f0000",
451	u64_max: u64::MAX => "000000000000000000",
452
453	u128_min: u128::MIN => "ffffffffffffffffffffffffffffffff",
454	u128_1: 1_u128 => "fffffffffffffffffffffffffffffffe",
455	u128_65535: 65535_u128 => "ffffffffffffffffffffffffffff0000",
456	u128_max: u128::MAX => "00000000000000000000000000000000",
457
458	bytes: ByteBuf::from(vec![0x01, 0xff]) => "01ff00ffff",
459	bytes_empty: ByteBuf::new() => "ffff",
460	bytes_escape: ByteBuf::from(vec![0x00, 0x01, 0x02]) => "000102ffff",
461
462	string: "foo".to_string() => "666f6fffff",
463	string_empty: "".to_string() => "ffff",
464	string_escape: "foo\x00bar".to_string() => "666f6f00626172ffff",
465	string_utf8: "👋".to_string() => "f09f918bffff",
466
467	tuple: (true, u64::MAX, ByteBuf::from(vec![0x00, 0x01])) => "000000000000000000000001ffff",
468	array_bool: [false, true, false] => "010001",
469	vec_bool: vec![false, true, false] => "010001",
470	vec_u64: vec![u64::MIN, u64::MAX, 65535_u64] => "ff0000000000000000003f0000",
471
472	enum_unit: Key::Unit => "00",
473	enum_newtype: Key::NewType("foo".to_string()) => "01666f6fffff",
474	enum_tuple: Key::Tuple(false, vec![0x00, 0x01], u64::MAX) => "02010001ffff000000000000000000",
475	enum_cow: Key::Cow(vec![0x00, 0x01].into(), false, String::from("foo").into()) => "030001ffff01666f6fffff",
476	enum_cow_borrow: Key::Cow([0x00, 0x01].as_slice().into(), false, "foo".into()) => "030001ffff01666f6fffff",
477
478	value_none: Value::none() => "00",
479	value_bool: Value::Boolean(true) => "0100",
480	value_float4: Value::Float4(OrderedF32::try_from(PI_F32).unwrap()) => "023fb6f024",
481	value_float8: Value::Float8(OrderedF64::try_from(PI_F64).unwrap()) => "033ff6de04abbbd2e7",
482	value_int1: Value::Int1(-1) => "0480",
483	value_int4: Value::Int4(123456) => "067ffe1dbf",
484	value_int8: Value::Int8(31415926) => "0701fffffffffe20a189",
485	value_int16: Value::Int16(-123456789012345678901234567890i128) => "08800000018ee90ff6c373e0ee4e3f0ad1",
486	value_string: Value::Utf8("foo".to_string()) => "09666f6fffff",
487	value_uint1: Value::Uint1(255) => "0a00",
488	value_uint2: Value::Uint2(65535) => "0b0000",
489	value_uint4: Value::Uint4(4294967295) => "0c0f00000000",
490	value_uint8: Value::Uint8(18446744073709551615) => "0d000000000000000000",
491	value_uint16: Value::Uint16(340282366920938463463374607431768211455u128) => "0e00000000000000000000000000000000",
492
493	// Option<bool>
494	option_none_bool: None::<bool> => "00",
495	option_some_true: Some(true) => "0100",
496	option_some_false: Some(false) => "0101",
497
498	// Option<f32>
499	option_none_f32: None::<f32> => "00",
500	option_some_f32: Some(PI_F32) => "013fb6f024",
501
502	// Option<f64>
503	option_none_f64: None::<f64> => "00",
504	option_some_f64: Some(PI_F64) => "013ff6de04abbbd2e7",
505
506	// Option<i8>
507	option_none_i8: None::<i8> => "00",
508	option_some_i8: Some(0i8) => "017f",
509
510	// Option<i16>
511	option_none_i16: None::<i16> => "00",
512	option_some_i16: Some(0i16) => "017fff",
513
514	// Option<i32>
515	option_none_i32: None::<i32> => "00",
516	option_some_i32: Some(0i32) => "017fffffff",
517
518	// Option<i64>
519	option_none_i64: None::<i64> => "00",
520	option_some_i64: Some(0i64) => "017f",
521
522	// Option<i128>
523	option_none_i128: None::<i128> => "00",
524	option_some_i128: Some(0i128) => "017fffffffffffffffffffffffffffffff",
525
526	// Option<u8>
527	option_none_u8: None::<u8> => "00",
528	option_some_u8: Some(0u8) => "01ff",
529
530	// Option<u16>
531	option_none_u16: None::<u16> => "00",
532	option_some_u16: Some(0u16) => "01ffff",
533
534	// Option<u32>
535	option_none_u32: None::<u32> => "00",
536	option_some_u32: Some(0u32) => "01ff",
537
538	// Option<u64>
539	option_none_u64: None::<u64> => "00",
540	option_some_u64: Some(0u64) => "01ff",
541
542	// Option<u128>
543	option_none_u128: None::<u128> => "00",
544	option_some_u128: Some(0u128) => "01ffffffffffffffffffffffffffffffff",
545
546	// Option<String>
547	option_none_string: None::<String> => "00",
548	option_some_string: Some("foo".to_string()) => "01666f6fffff",
549	option_some_empty_string: Some("".to_string()) => "01ffff",
550
551	// Option<ByteBuf>
552	option_none_bytes: None::<ByteBuf> => "00",
553	option_some_bytes: Some(ByteBuf::from(vec![0x01, 0xff])) => "0101ff00ffff",
554
555	// Nested Option<Option<bool>>
556	option_nested_none: None::<Option<bool>> => "00",
557	option_nested_some_none: Some(None::<bool>) => "0100",
558	option_nested_some_some_true: Some(Some(true)) => "010100",
559	option_nested_some_some_false: Some(Some(false)) => "010101",
560
561	// Nested Option<Option<i32>>
562	option_nested_none_i32: None::<Option<i32>> => "00",
563	option_nested_some_none_i32: Some(None::<i32>) => "0100",
564	option_nested_some_some_i32: Some(Some(0i32)) => "01017fffffff",
565
566	// Nested Option<Option<String>>
567	option_nested_some_some_string: Some(Some("foo".to_string())) => "0101666f6fffff",
568
569	// Triple nested Option<Option<Option<bool>>>
570	option_triple_none: None::<Option<Option<bool>>> => "00",
571	option_triple_some_none: Some(None::<Option<bool>>) => "0100",
572	option_triple_some_some_none: Some(Some(None::<bool>)) => "010100",
573	option_triple_some_some_some: Some(Some(Some(true))) => "01010100",}
574
575	#[test]
576	fn test_option_ordering() {
577		// Descending: None > Some(MAX) > Some(0) > Some(MIN)
578		// Byte order: None < Some(MAX) < Some(0) < Some(MIN)
579		let none = serialize(&None::<i32>);
580		let some_max = serialize(&Some(i32::MAX));
581		let some_zero = serialize(&Some(0i32));
582		let some_min = serialize(&Some(i32::MIN));
583		assert!(none < some_max);
584		assert!(some_max < some_zero);
585		assert!(some_zero < some_min);
586	}
587
588	#[test]
589	fn test_nested_option_ordering() {
590		let none = serialize(&None::<Option<bool>>);
591		let some_none = serialize(&Some(None::<bool>));
592		let some_some_true = serialize(&Some(Some(true)));
593		let some_some_false = serialize(&Some(Some(false)));
594		assert!(none < some_none);
595		assert!(some_none < some_some_true);
596		assert!(some_some_true < some_some_false);
597	}
598
599	#[test]
600	fn test_key_serializer() {
601		// Test bool
602		let mut s = KeySerializer::new();
603		s.extend_bool(true);
604		assert_eq!(s.finish(), vec![0x00]);
605
606		let mut s = KeySerializer::new();
607		s.extend_bool(false);
608		assert_eq!(s.finish(), vec![0x01]);
609
610		// Test u64
611		let mut s = KeySerializer::new();
612		s.extend_u64(0u64);
613		assert_eq!(s.finish(), vec![0xff]);
614
615		// Test i64
616		let mut s = KeySerializer::new();
617		s.extend_i64(0i64);
618		assert_eq!(s.finish(), vec![0x7f]);
619
620		// Test f32
621		let mut s = KeySerializer::new();
622		s.extend_f32(0.0f32);
623		assert_eq!(s.finish(), vec![0x7f, 0xff, 0xff, 0xff]);
624
625		// Test f64
626		let mut s = KeySerializer::new();
627		s.extend_f64(0.0f64);
628		assert_eq!(s.finish(), vec![0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]);
629
630		// Test bytes
631		let mut s = KeySerializer::new();
632		s.extend_bytes(b"foo");
633		assert_eq!(s.finish(), vec![0x66, 0x6f, 0x6f, 0xff, 0xff]);
634
635		// Test chaining
636		let mut s = KeySerializer::with_capacity(32);
637		s.extend_bool(true).extend_u32(1u32).extend_i16(-1i16).extend_bytes(b"test");
638		let result = s.finish();
639		assert!(!result.is_empty());
640		assert!(result.len() >= 10); // Should have all the encoded values
641	}
642}