use super::{
Column,
ColumnRef,
};
use crate::{
types::Type,
Error,
Result,
};
use bytes::BytesMut;
use std::sync::Arc;
pub struct ColumnIpv4 {
type_: Type,
data: Arc<super::ColumnUInt32>,
}
impl ColumnIpv4 {
pub fn new(type_: Type) -> Self {
Self { type_, data: Arc::new(super::ColumnUInt32::new()) }
}
pub fn with_data(mut self, data: Vec<u32>) -> Self {
self.data =
Arc::new(super::ColumnUInt32::from_vec(Type::uint32(), data));
self
}
pub fn append_from_string(&mut self, s: &str) -> Result<()> {
let parts: Vec<&str> = s.split('.').collect();
if parts.len() != 4 {
return Err(Error::Protocol(format!(
"Invalid IPv4 format: {}",
s
)));
}
let mut ip: u32 = 0;
for (i, part) in parts.iter().enumerate() {
let octet = part.parse::<u8>().map_err(|e| {
Error::Protocol(format!("Invalid IPv4 octet: {}", e))
})?;
ip |= (octet as u32) << (24 - i * 8);
}
self.append(ip);
Ok(())
}
pub fn append(&mut self, value: u32) {
Arc::get_mut(&mut self.data)
.expect("Cannot append to shared column")
.append(value);
}
pub fn at(&self, index: usize) -> u32 {
self.data.at(index)
}
pub fn as_string(&self, index: usize) -> String {
let ip = self.data.at(index);
format!(
"{}.{}.{}.{}",
(ip >> 24) & 0xFF,
(ip >> 16) & 0xFF,
(ip >> 8) & 0xFF,
ip & 0xFF
)
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn data(&self) -> &super::ColumnUInt32 {
&self.data
}
}
impl Column for ColumnIpv4 {
fn column_type(&self) -> &Type {
&self.type_
}
fn size(&self) -> usize {
self.data.size()
}
fn clear(&mut self) {
Arc::get_mut(&mut self.data)
.expect("Cannot clear shared column")
.clear();
}
fn reserve(&mut self, new_cap: usize) {
Arc::get_mut(&mut self.data)
.expect("Cannot reserve on shared column")
.reserve(new_cap);
}
fn append_column(&mut self, other: ColumnRef) -> Result<()> {
let other =
other.as_any().downcast_ref::<ColumnIpv4>().ok_or_else(|| {
Error::TypeMismatch {
expected: self.type_.name(),
actual: other.column_type().name(),
}
})?;
Arc::get_mut(&mut self.data)
.expect("Cannot append to shared column")
.append_column(other.data.clone() as ColumnRef)?;
Ok(())
}
fn load_from_buffer(
&mut self,
buffer: &mut &[u8],
rows: usize,
) -> Result<()> {
Arc::get_mut(&mut self.data)
.expect("Cannot load into shared column")
.load_from_buffer(buffer, rows)
}
fn save_to_buffer(&self, buffer: &mut BytesMut) -> Result<()> {
self.data.save_to_buffer(buffer)
}
fn clone_empty(&self) -> ColumnRef {
Arc::new(ColumnIpv4::new(self.type_.clone()))
}
fn slice(&self, begin: usize, len: usize) -> Result<ColumnRef> {
let sliced_data = self.data.slice(begin, len)?;
Ok(Arc::new(ColumnIpv4 {
type_: self.type_.clone(),
data: sliced_data
.as_any()
.downcast_ref::<super::ColumnUInt32>()
.map(|col| {
Arc::new(super::ColumnUInt32::from_vec(
Type::uint32(),
col.data().to_vec(),
))
})
.expect("Slice should return ColumnUInt32"),
}))
}
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_ipv4_from_string() {
let mut col = ColumnIpv4::new(Type::ipv4());
col.append_from_string("192.168.1.1").unwrap();
col.append_from_string("10.0.0.1").unwrap();
col.append_from_string("0.0.0.0").unwrap();
assert_eq!(col.len(), 3);
assert_eq!(col.as_string(0), "192.168.1.1");
assert_eq!(col.as_string(1), "10.0.0.1");
assert_eq!(col.as_string(2), "0.0.0.0");
}
#[test]
fn test_ipv4_from_u32() {
let mut col = ColumnIpv4::new(Type::ipv4());
col.append(0xC0A80101); col.append(0x0A000001); col.append(0);
assert_eq!(col.len(), 3);
assert_eq!(col.at(0), 0xC0A80101);
assert_eq!(col.at(1), 0x0A000001);
assert_eq!(col.at(2), 0);
}
#[test]
fn test_ipv4_edge_cases() {
let mut col = ColumnIpv4::new(Type::ipv4());
col.append_from_string("255.255.255.255").unwrap();
col.append_from_string("127.0.0.1").unwrap();
assert_eq!(col.as_string(0), "255.255.255.255");
assert_eq!(col.as_string(1), "127.0.0.1");
}
}