use regex::Regex;
use super::data::InitiatorType;
use super::error::*;
struct SizeUnit<'a> {
unit: &'a str,
bytes: u64,
}
const SIZE_CONVS: [SizeUnit<'static>; 6] = [
SizeUnit {
unit: "EiB",
bytes: 1u64 << 60,
},
SizeUnit {
unit: "PiB",
bytes: 1u64 << 50,
},
SizeUnit {
unit: "TiB",
bytes: 1u64 << 40,
},
SizeUnit {
unit: "GiB",
bytes: 1u64 << 30,
},
SizeUnit {
unit: "MiB",
bytes: 1u64 << 20,
},
SizeUnit {
unit: "KiB",
bytes: 1u64 << 10,
},
];
const EXTRA_SIZE_CONVS: [SizeUnit<'static>; 7] = [
SizeUnit {
unit: "B",
bytes: 1u64,
},
SizeUnit {
unit: "KB",
bytes: 1_000u64,
},
SizeUnit {
unit: "MB",
bytes: 1_000_000u64,
},
SizeUnit {
unit: "GB",
bytes: 1_000_000_000u64,
},
SizeUnit {
unit: "TB",
bytes: 1_000_000_000_000u64,
},
SizeUnit {
unit: "PB",
bytes: 1_000_000_000_000_000u64,
},
SizeUnit {
unit: "EB",
bytes: 1_000_000_000_000_000_000u64,
},
];
pub fn size_human_2_size_bytes(s: &str) -> u64 {
let regex_size_human = match Regex::new(
r"(?x)
^
([0-9\.]+) # 1: number
[\ \t]* # might have space between number and unit
([a-zA-Z]*) # 2: units
$
",
) {
Ok(r) => r,
Err(_) => return 0,
};
let cap = match regex_size_human.captures(s) {
Some(c) => c,
None => return 0,
};
let number = match cap.get(1) {
Some(n) => n.as_str().parse::<f64>().unwrap_or(0f64),
None => return 0,
};
let unit = match cap.get(2) {
Some(u) => {
let tmp = u.as_str().to_uppercase();
println!("tmp: {}", tmp);
if !tmp.ends_with('B') {
format!("{}IB", tmp)
} else {
tmp
}
}
None => return 0,
};
for size_conv in &SIZE_CONVS {
if size_conv.unit.to_uppercase() == unit {
return (size_conv.bytes as f64 * number) as u64;
}
}
for size_conv in &EXTRA_SIZE_CONVS {
if size_conv.unit == unit {
return (size_conv.bytes as f64 * number) as u64;
}
}
0
}
pub fn size_bytes_2_size_human(i: u64) -> String {
let mut unit = "B";
let mut num: f64 = 0f64;
for size_conv in &SIZE_CONVS {
if i >= size_conv.bytes {
num = (i as f64) / (size_conv.bytes as f64);
unit = size_conv.unit;
break;
}
}
if num == 0f64 {
num = i as f64;
}
format!("{:.2}{}", num, unit)
}
pub(crate) fn verify_init_id_str(init_id: &str, init_type: InitiatorType) -> Result<()> {
let valid: bool = match init_type {
InitiatorType::Wwpn => {
let regex_wwpn = Regex::new(
r"(?x)
^(?:0x|0X)?(?:[0-9A-Fa-f]{2})
(?:(?:[\.:\-])?[0-9A-Fa-f]{2}){7}$
",
)?;
regex_wwpn.is_match(init_id)
}
InitiatorType::IscsiIqn => {
init_id.starts_with("iqn") || init_id.starts_with("eui") || init_id.starts_with("naa")
}
_ => {
return Err(LsmError::InvalidArgument(format!(
"Invalid init_type {}, should be \
InitiatorType::Wwpn or InitiatorType::IscsiIqn.",
init_type as i32
)))
}
};
if valid {
Ok(())
} else {
Err(LsmError::InvalidArgument(format!(
"Invalid initiator ID string '{}'",
init_id
)))
}
}