use super::{
Column,
ColumnRef,
};
use crate::{
types::Type,
Error,
Result,
};
use bytes::BytesMut;
use std::sync::Arc;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Uuid {
pub high: u64,
pub low: u64,
}
impl Uuid {
pub fn new(high: u64, low: u64) -> Self {
Self { high, low }
}
pub fn parse(s: &str) -> Result<Self> {
let s = s.replace("-", "");
if s.len() != 32 {
return Err(Error::Protocol(format!(
"Invalid UUID format: {}",
s
)));
}
let high = u64::from_str_radix(&s[0..16], 16).map_err(|e| {
Error::Protocol(format!("Invalid UUID hex: {}", e))
})?;
let low = u64::from_str_radix(&s[16..32], 16).map_err(|e| {
Error::Protocol(format!("Invalid UUID hex: {}", e))
})?;
Ok(Self { high, low })
}
pub fn as_string(&self) -> String {
format!(
"{:08x}-{:04x}-{:04x}-{:04x}-{:012x}",
(self.high >> 32) as u32,
((self.high >> 16) & 0xFFFF) as u16,
(self.high & 0xFFFF) as u16,
(self.low >> 48) as u16,
self.low & 0xFFFFFFFFFFFF,
)
}
}
impl std::fmt::Display for Uuid {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_string())
}
}
pub struct ColumnUuid {
type_: Type,
data: Vec<Uuid>,
}
impl ColumnUuid {
pub fn new(type_: Type) -> Self {
Self { type_, data: Vec::new() }
}
pub fn with_data(mut self, data: Vec<Uuid>) -> Self {
self.data = data;
self
}
pub fn append(&mut self, value: Uuid) {
self.data.push(value);
}
pub fn append_from_string(&mut self, s: &str) -> Result<()> {
let uuid = Uuid::parse(s)?;
self.data.push(uuid);
Ok(())
}
pub fn at(&self, index: usize) -> Uuid {
self.data[index]
}
pub fn as_string(&self, index: usize) -> String {
self.data[index].as_string()
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
}
impl Column for ColumnUuid {
fn column_type(&self) -> &Type {
&self.type_
}
fn size(&self) -> usize {
self.data.len()
}
fn clear(&mut self) {
self.data.clear();
}
fn reserve(&mut self, new_cap: usize) {
self.data.reserve(new_cap);
}
fn append_column(&mut self, other: ColumnRef) -> Result<()> {
let other =
other.as_any().downcast_ref::<ColumnUuid>().ok_or_else(|| {
Error::TypeMismatch {
expected: self.type_.name(),
actual: other.column_type().name(),
}
})?;
self.data.extend_from_slice(&other.data);
Ok(())
}
fn load_from_buffer(
&mut self,
buffer: &mut &[u8],
rows: usize,
) -> Result<()> {
let bytes_needed = rows * 16;
if buffer.len() < bytes_needed {
return Err(Error::Protocol(format!(
"Buffer underflow: need {} bytes for UUID, have {}",
bytes_needed,
buffer.len()
)));
}
self.data.reserve(rows);
let current_len = self.data.len();
unsafe {
self.data.set_len(current_len + rows);
let dest_ptr =
(self.data.as_mut_ptr() as *mut u8).add(current_len * 16);
std::ptr::copy_nonoverlapping(
buffer.as_ptr(),
dest_ptr,
bytes_needed,
);
}
use bytes::Buf;
buffer.advance(bytes_needed);
Ok(())
}
fn save_to_buffer(&self, buffer: &mut BytesMut) -> Result<()> {
if !self.data.is_empty() {
let byte_slice = unsafe {
std::slice::from_raw_parts(
self.data.as_ptr() as *const u8,
self.data.len() * 16,
)
};
buffer.extend_from_slice(byte_slice);
}
Ok(())
}
fn clone_empty(&self) -> ColumnRef {
Arc::new(ColumnUuid::new(self.type_.clone()))
}
fn slice(&self, begin: usize, len: usize) -> Result<ColumnRef> {
if begin + len > self.data.len() {
return Err(Error::InvalidArgument(format!(
"Slice out of bounds: begin={}, len={}, size={}",
begin,
len,
self.data.len()
)));
}
let sliced_data = self.data[begin..begin + len].to_vec();
Ok(Arc::new(
ColumnUuid::new(self.type_.clone()).with_data(sliced_data),
))
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
}
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
mod tests {
use super::*;
#[test]
fn test_uuid_parse() {
let uuid =
Uuid::parse("550e8400-e29b-41d4-a716-446655440000").unwrap();
assert_eq!(uuid.high, 0x550e8400e29b41d4);
assert_eq!(uuid.low, 0xa716446655440000);
}
#[test]
fn test_uuid_to_string() {
let uuid = Uuid::new(0x550e8400e29b41d4, 0xa716446655440000);
assert_eq!(uuid.as_string(), "550e8400-e29b-41d4-a716-446655440000");
assert_eq!(
format!("{}", uuid),
"550e8400-e29b-41d4-a716-446655440000"
);
}
#[test]
fn test_uuid_column_append() {
let mut col = ColumnUuid::new(Type::uuid());
col.append(Uuid::new(0x123456789abcdef0, 0xfedcba9876543210));
col.append(Uuid::new(0, 0));
assert_eq!(col.len(), 2);
assert_eq!(
col.at(0),
Uuid::new(0x123456789abcdef0, 0xfedcba9876543210)
);
assert_eq!(col.at(1), Uuid::new(0, 0));
}
#[test]
fn test_uuid_column_from_string() {
let mut col = ColumnUuid::new(Type::uuid());
col.append_from_string("550e8400-e29b-41d4-a716-446655440000")
.unwrap();
assert_eq!(col.len(), 1);
assert_eq!(col.as_string(0), "550e8400-e29b-41d4-a716-446655440000");
}
}