use super::*;
use chrono::{DateTime, Utc};
pub fn on_key(top: impl AsRef<[u8]>, on: u64, sep: Option<[u8; 1]>) -> Vec<u8> {
let top_bytes = top.as_ref();
let sep_bytes = sep.map_or(b".".to_vec(), |s| s.to_vec());
let mut result = Vec::with_capacity(top_bytes.len() + sep_bytes.len() + 32);
result.extend_from_slice(top_bytes);
result.extend_from_slice(sep_bytes.as_slice());
let hex_str = format!("{:032x}", on);
result.extend_from_slice(hex_str.as_bytes());
result
}
pub fn sn_key(pre: impl AsRef<[u8]>, sn: u64) -> Vec<u8> {
on_key(pre, sn, Some(*b"."))
}
pub fn fn_key(pre: impl AsRef<[u8]>, fn_val: u64) -> Vec<u8> {
on_key(pre, fn_val, Some(*b"."))
}
pub fn dg_key(pre: impl AsRef<[u8]>, dig: impl AsRef<[u8]>) -> Vec<u8> {
let pre_bytes = pre.as_ref();
let dig_bytes = dig.as_ref();
let mut result = Vec::with_capacity(pre_bytes.len() + 1 + dig_bytes.len());
result.extend_from_slice(pre_bytes);
result.push(b'.');
result.extend_from_slice(dig_bytes);
result
}
pub fn dt_key(pre: impl AsRef<[u8]>, dts: impl AsRef<[u8]>) -> Vec<u8> {
let pre_bytes = pre.as_ref();
let dts_bytes = dts.as_ref();
let mut result = Vec::with_capacity(pre_bytes.len() + 1 + dts_bytes.len());
result.extend_from_slice(pre_bytes);
result.push(b'|');
result.extend_from_slice(dts_bytes);
result
}
pub fn split_key(
key: impl AsRef<[u8]>,
sep: Option<[u8; 1]>,
) -> Result<(Vec<u8>, Vec<u8>), DBError> {
let key_bytes = key.as_ref();
let sep_bytes = sep.map_or(b".".to_vec(), |s| s.to_vec());
if let Some(pos) = key_bytes.iter().rposition(|&b| b == sep_bytes[0]) {
if sep_bytes.len() == 1 || key_bytes[pos..pos + sep_bytes.len()] == sep_bytes[..] {
let (pre, suf) = key_bytes.split_at(pos);
let suf = &suf[sep_bytes.len()..];
return Ok((pre.to_vec(), suf.to_vec()));
}
}
Err(DBError::ValueError(format!(
"Unsplittable key at {:?}",
sep_bytes
)))
}
pub fn split_on_key(
key: impl AsRef<[u8]>,
sep: Option<[u8; 1]>,
) -> Result<(Vec<u8>, u64), DBError> {
let (top, on_bytes) = split_key(key, sep)?;
let on_str = String::from_utf8(on_bytes)
.map_err(|e| DBError::ParseError(format!("Invalid UTF-8 in ordinal: {}", e)))?;
let on = u64::from_str_radix(&on_str, 16)
.map_err(|e| DBError::ParseError(format!("Invalid hex in ordinal {}: {}", on_str, e)))?;
Ok((top, on))
}
pub fn split_sn_key(
key: impl AsRef<[u8]>,
sep: Option<[u8; 1]>,
) -> Result<(Vec<u8>, u64), DBError> {
split_on_key(key, sep)
}
pub fn split_fn_key(
key: impl AsRef<[u8]>,
sep: Option<[u8; 1]>,
) -> Result<(Vec<u8>, u64), DBError> {
split_on_key(key, sep)
}
pub fn split_key_on(
key: impl AsRef<[u8]>,
sep: Option<[u8; 1]>,
) -> Result<(Vec<u8>, u64), DBError> {
split_on_key(key, sep)
}
pub fn split_key_sn(
key: impl AsRef<[u8]>,
sep: Option<[u8; 1]>,
) -> Result<(Vec<u8>, u64), DBError> {
split_on_key(key, sep)
}
pub fn split_key_fn(
key: impl AsRef<[u8]>,
sep: Option<[u8; 1]>,
) -> Result<(Vec<u8>, u64), DBError> {
split_on_key(key, sep)
}
pub fn split_key_dt(key: impl AsRef<[u8]>) -> Result<(Vec<u8>, DateTime<Utc>), DBError> {
let (pre, dts_bytes) = split_key(key, Some(*b"|"))?;
let dts = String::from_utf8(dts_bytes)
.map_err(|e| DBError::ParseError(format!("Invalid UTF-8 in datetime: {}", e)))?;
let dt = DateTime::parse_from_rfc3339(&dts)
.map_err(|e| DBError::ParseError(format!("Invalid datetime format: {}", e)))?
.with_timezone(&Utc);
Ok((pre, dt))
}
pub fn suffix(key: impl AsRef<[u8]>, ion: u64, sep: Option<[u8; 1]>) -> Vec<u8> {
let key_bytes = key.as_ref();
let sep_bytes = sep.map_or(b".".to_vec(), |s| s.to_vec());
let ion_str = format!("{:032x}", ion);
let mut result = Vec::with_capacity(key_bytes.len() + sep_bytes.len() + 32);
result.extend_from_slice(key_bytes);
result.extend_from_slice(sep_bytes.as_slice());
result.extend_from_slice(ion_str.as_bytes());
result
}
pub fn unsuffix(iokey: impl AsRef<[u8]>, sep: Option<[u8; 1]>) -> Result<(Vec<u8>, u64), DBError> {
let iokey_bytes = iokey.as_ref();
let sep_bytes = sep.map_or(b".".to_vec(), |s| s.to_vec());
if let Some(pos) = iokey_bytes
.windows(sep_bytes.len())
.rposition(|window| window == sep_bytes)
{
let (key, ion_with_sep) = iokey_bytes.split_at(pos);
let ion_bytes = &ion_with_sep[sep_bytes.len()..];
let ion_str = String::from_utf8(ion_bytes.to_vec())
.map_err(|e| DBError::ParseError(format!("Invalid UTF-8 in ion: {}", e)))?;
let ion = u64::from_str_radix(&ion_str, 16)
.map_err(|e| DBError::ParseError(format!("Invalid hex in ion: {}", e)))?;
return Ok((key.to_vec(), ion));
}
Err(DBError::ValueError(format!(
"Unsplittable iokey at {:?}",
sep_bytes
)))
}
#[cfg(test)]
mod tests {
use super::*;
use chrono::{DateTime, Utc};
#[test]
fn test_key_funcs() {
let pre = b"BAzwEHHzq7K0gzQPYGGwTmuupUhPx5_yZ-Wk1x4ejhcc".to_vec();
let dig = b"EGAPkzNZMtX-QiVgbRbyAIZGoXvbGv9IPb0foWTZvI_4".to_vec();
let sn = 3;
let dts = b"2021-02-13T19:16:50.750302+00:00".to_vec();
assert_eq!(
on_key(&pre, 0, None),
[
pre.as_slice(),
b".00000000000000000000000000000000".as_slice()
]
.concat()
);
assert_eq!(
on_key(&pre, 1, None),
[
pre.as_slice(),
b".00000000000000000000000000000001".as_slice()
]
.concat()
);
assert_eq!(
on_key(&pre, 2, None),
[
pre.as_slice(),
b".00000000000000000000000000000002".as_slice()
]
.concat()
);
assert_eq!(
on_key(&pre, 3, None),
[
pre.as_slice(),
b".00000000000000000000000000000003".as_slice()
]
.concat()
);
assert_eq!(
on_key(&pre, 4, None),
[
pre.as_slice(),
b".00000000000000000000000000000004".as_slice()
]
.concat()
);
assert_eq!(
on_key(&pre, 0, Some(*b"|")),
[
pre.as_slice(),
b"|00000000000000000000000000000000".as_slice()
]
.concat()
);
assert_eq!(
on_key(&pre, 4, Some(*b"|")),
[
pre.as_slice(),
b"|00000000000000000000000000000004".as_slice()
]
.concat()
);
let onkey = on_key(&pre, 0, None);
assert_eq!(
split_key(&onkey, None).unwrap(),
(pre.clone(), format!("{:032x}", 0).as_bytes().to_vec())
);
assert_eq!(split_on_key(&onkey, None).unwrap(), (pre.clone(), 0));
let onkey = on_key(&pre, 1, None);
assert_eq!(
split_key(&onkey, None).unwrap(),
(pre.clone(), format!("{:032x}", 1).as_bytes().to_vec())
);
assert_eq!(split_on_key(&onkey, None).unwrap(), (pre.clone(), 1));
let onkey = on_key(&pre, 15, None);
assert_eq!(
split_key(&onkey, None).unwrap(),
(pre.clone(), format!("{:032x}", 15).as_bytes().to_vec())
);
assert_eq!(split_on_key(&onkey, None).unwrap(), (pre.clone(), 15));
let onkey = on_key(&pre, 0, Some(*b"|"));
assert_eq!(
split_key(&onkey, Some(*b"|")).unwrap(),
(pre.clone(), format!("{:032x}", 0).as_bytes().to_vec())
);
assert_eq!(split_on_key(&onkey, Some(*b"|")).unwrap(), (pre.clone(), 0));
let onkey = on_key(&pre, 15, Some(*b"|"));
assert_eq!(
split_key(&onkey, Some(*b"|")).unwrap(),
(pre.clone(), format!("{:032x}", 15).as_bytes().to_vec())
);
assert_eq!(
split_on_key(&onkey, Some(*b"|")).unwrap(),
(pre.clone(), 15)
);
assert_eq!(
sn_key(&pre, sn),
b"BAzwEHHzq7K0gzQPYGGwTmuupUhPx5_yZ-Wk1x4ejhcc.00000000000000000000000000000003"
.to_vec()
);
assert_eq!(
split_key(&sn_key(&pre, sn), None).unwrap(),
(pre.clone(), format!("{:032x}", sn).as_bytes().to_vec())
);
assert_eq!(
split_sn_key(&sn_key(&pre, sn), None).unwrap(),
(pre.clone(), sn)
);
assert_eq!(
dg_key(&pre, &dig),
b"BAzwEHHzq7K0gzQPYGGwTmuupUhPx5_yZ-Wk1x4ejhcc.EGAPkzNZMtX-QiVgbRbyAIZGoXvbGv9IPb0foWTZvI_4".to_vec()
);
assert_eq!(
split_key(&dg_key(&pre, &dig), None).unwrap(),
(pre.clone(), dig.clone())
);
assert_eq!(
dt_key(&pre, &dts),
b"BAzwEHHzq7K0gzQPYGGwTmuupUhPx5_yZ-Wk1x4ejhcc|2021-02-13T19:16:50.750302+00:00"
.to_vec()
);
assert_eq!(
split_key(&dt_key(&pre, &dts), Some(*b"|")).unwrap(),
(pre.clone(), dts.clone())
);
let datetime = DateTime::parse_from_rfc3339("2021-02-13T19:16:50.750302+00:00")
.unwrap()
.with_timezone(&Utc);
assert_eq!(split_key_dt(&dt_key(&pre, &dts)).unwrap().0, pre.clone());
let pre_str = "BAzwEHHzq7K0gzQPYGGwTmuupUhPx5_yZ-Wk1x4ejhcc";
let dig_str = "EGAPkzNZMtX-QiVgbRbyAIZGoXvbGv9IPb0foWTZvI_4";
let dts_str = "2021-02-13T19:16:50.750302+00:00";
assert_eq!(
sn_key(pre_str, sn),
b"BAzwEHHzq7K0gzQPYGGwTmuupUhPx5_yZ-Wk1x4ejhcc.00000000000000000000000000000003"
.to_vec()
);
let sn_key_str = String::from_utf8(sn_key(pre_str, sn)).unwrap();
assert_eq!(
split_key(&sn_key_str, None).unwrap(),
(
pre_str.as_bytes().to_vec(),
format!("{:032x}", sn).as_bytes().to_vec()
)
);
assert_eq!(
split_sn_key(&sn_key_str, None).unwrap(),
(pre_str.as_bytes().to_vec(), sn)
);
assert_eq!(
dg_key(pre_str, dig_str),
b"BAzwEHHzq7K0gzQPYGGwTmuupUhPx5_yZ-Wk1x4ejhcc.EGAPkzNZMtX-QiVgbRbyAIZGoXvbGv9IPb0foWTZvI_4".to_vec()
);
let dg_key_str = String::from_utf8(dg_key(pre_str, dig_str)).unwrap();
assert_eq!(
split_key(&dg_key_str, None).unwrap(),
(pre_str.as_bytes().to_vec(), dig_str.as_bytes().to_vec())
);
assert_eq!(
dt_key(pre_str, dts_str),
b"BAzwEHHzq7K0gzQPYGGwTmuupUhPx5_yZ-Wk1x4ejhcc|2021-02-13T19:16:50.750302+00:00"
.to_vec()
);
let dt_key_str = String::from_utf8(dt_key(pre_str, dts_str)).unwrap();
assert_eq!(
split_key(&dt_key_str, Some(*b"|")).unwrap(),
(pre_str.as_bytes().to_vec(), dts_str.as_bytes().to_vec())
);
let datetime_str = DateTime::parse_from_rfc3339(dts_str)
.unwrap()
.with_timezone(&Utc);
assert_eq!(
split_key_dt(&dt_key_str).unwrap().0,
pre_str.as_bytes().to_vec()
);
let result = split_key(pre.as_slice(), None);
assert!(result.is_err());
let nested_key = dg_key(&pre, &dg_key(&pre, &dig));
let (_, _) = split_key(&nested_key, None).unwrap();
}
#[test]
fn test_suffix() {
const SUFFIX_SIZE: usize = 32;
const MAX_SUFFIX: u128 = u128::MAX;
assert_eq!(SUFFIX_SIZE, 32);
assert_eq!(MAX_SUFFIX, 340282366920938463463374607431768211455);
let key = "ABCDEFG.FFFFFF";
let keyb = b"ABCDEFG.FFFFFF";
let ion = 0;
let iokey = suffix(key, ion, None);
assert_eq!(
iokey,
b"ABCDEFG.FFFFFF.00000000000000000000000000000000".to_vec()
);
let (k, i) = unsuffix(&iokey, None).unwrap();
assert_eq!(k, keyb.to_vec());
assert_eq!(i, ion);
let ion = 64;
let iokey = suffix(keyb, ion, None);
assert_eq!(
iokey,
b"ABCDEFG.FFFFFF.00000000000000000000000000000040".to_vec()
);
let (k, i) = unsuffix(&iokey, None).unwrap();
assert_eq!(k, keyb.to_vec());
assert_eq!(i, ion);
let iokey = suffix(key, MAX_SUFFIX as u64, None);
println!("{}", String::from_utf8_lossy(&iokey));
let (k, i) = unsuffix(&iokey, None).unwrap();
assert_eq!(k, keyb.to_vec());
assert_eq!(i, MAX_SUFFIX as u64);
}
}