Skip to main content

reifydb_type/value/blob/
mod.rs

1// SPDX-License-Identifier: MIT
2// Copyright (c) 2025 ReifyDB
3
4use std::{
5	fmt,
6	fmt::{Display, Formatter},
7	ops::Deref,
8};
9
10use serde::{Deserialize, Serialize};
11
12use crate::util;
13
14pub mod base58;
15pub mod base64;
16pub mod hex;
17pub mod utf8;
18
19/// A binary large object (BLOB) wrapper type
20#[repr(transparent)]
21#[derive(Default, Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
22pub struct Blob(Vec<u8>);
23
24impl Blob {
25	/// Create a new BLOB from raw bytes
26	pub fn new(bytes: Vec<u8>) -> Self {
27		Self(bytes)
28	}
29
30	pub fn empty() -> Self {
31		Self(Vec::with_capacity(0))
32	}
33
34	/// Create a BLOB from a byte slice
35	pub fn from_slice(bytes: &[u8]) -> Self {
36		Self(Vec::from(bytes.to_vec()))
37	}
38
39	/// Get the raw bytes
40	pub fn as_bytes(&self) -> &[u8] {
41		&self.0
42	}
43
44	/// Get the length in bytes
45	pub fn len(&self) -> usize {
46		self.0.len()
47	}
48
49	/// Check if the BLOB is empty
50	pub fn is_empty(&self) -> bool {
51		self.0.is_empty()
52	}
53
54	/// Convert into the inner bytes
55	pub fn into_bytes(self) -> Vec<u8> {
56		self.0.to_vec()
57	}
58}
59
60impl Deref for Blob {
61	type Target = [u8];
62
63	fn deref(&self) -> &Self::Target {
64		&self.0
65	}
66}
67
68impl From<Vec<u8>> for Blob {
69	fn from(bytes: Vec<u8>) -> Self {
70		Self::new(bytes)
71	}
72}
73
74impl From<&[u8]> for Blob {
75	fn from(bytes: &[u8]) -> Self {
76		Self::from_slice(bytes)
77	}
78}
79
80impl From<Blob> for Vec<u8> {
81	fn from(blob: Blob) -> Self {
82		blob.into_bytes()
83	}
84}
85
86impl Display for Blob {
87	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
88		write!(f, "0x{}", util::hex::encode(self.as_bytes()))
89	}
90}
91
92#[cfg(test)]
93pub mod tests {
94	use super::*;
95
96	#[test]
97	fn test_blob_from_bytes() {
98		let data = vec![0xDE, 0xAD, 0xBE, 0xEF];
99		let blob = Blob::new(data.clone());
100		assert_eq!(blob.as_bytes(), &data);
101		assert_eq!(blob.len(), 4);
102		assert!(!blob.is_empty());
103	}
104
105	#[test]
106	fn test_blob_from_slice() {
107		let data = [0xCA, 0xFE, 0xBA, 0xBE];
108		let blob = Blob::from_slice(&data);
109		assert_eq!(blob.as_bytes(), &data);
110	}
111
112	#[test]
113	fn test_blob_deref() {
114		let blob = Blob::new(vec![1, 2, 3]);
115		let bytes: &[u8] = &blob;
116		assert_eq!(bytes, &[1, 2, 3]);
117	}
118
119	#[test]
120	fn test_blob_conversions() {
121		let data = vec![0xFF, 0x00, 0xFF];
122		let blob = Blob::from(data.clone());
123		let bytes: Vec<u8> = blob.into();
124		assert_eq!(bytes, data);
125	}
126
127	#[test]
128	fn test_blob_display() {
129		let blob = Blob::new(vec![0xDE, 0xAD, 0xBE, 0xEF]);
130		assert_eq!(format!("{}", blob), "0xdeadbeef");
131
132		let empty_blob = Blob::new(vec![]);
133		assert_eq!(format!("{}", empty_blob), "0x");
134
135		let single_byte_blob = Blob::new(vec![0xFF]);
136		assert_eq!(format!("{}", single_byte_blob), "0xff");
137	}
138}