mirror of
https://github.com/mbilker/vgpu_unlock-rs.git
synced 2025-06-08 13:28:23 +02:00
human_number: add parser for human-readable sizes
This commit is contained in:
parent
7490f5bfbc
commit
375386e67c
148
src/human_number.rs
Normal file
148
src/human_number.rs
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
use std::convert::TryInto;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use serde::de::{Deserializer, Error, Unexpected, Visitor};
|
||||||
|
|
||||||
|
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
deserializer.deserialize_any(HumanNumberVisitor)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct HumanNumberVisitor;
|
||||||
|
|
||||||
|
impl<'de> Visitor<'de> for HumanNumberVisitor {
|
||||||
|
type Value = Option<u64>;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
formatter.write_str("unsigned number or quoted human-readable unsigned number")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: Error,
|
||||||
|
{
|
||||||
|
v.try_into()
|
||||||
|
.map_err(Error::custom)
|
||||||
|
.and_then(|v| self.visit_u64(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: Error,
|
||||||
|
{
|
||||||
|
Ok(Some(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: Error,
|
||||||
|
{
|
||||||
|
let v = v.trim();
|
||||||
|
|
||||||
|
if v.is_empty() {
|
||||||
|
return Err(Error::invalid_value(
|
||||||
|
Unexpected::Str(v),
|
||||||
|
&"non-empty string",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Using `bytes` instead of `chars` here because `split_at` takes a byte offset
|
||||||
|
match v
|
||||||
|
.bytes()
|
||||||
|
.map(|byte| byte as char)
|
||||||
|
.position(|ch| !(ch.is_numeric() || ch == '.'))
|
||||||
|
{
|
||||||
|
Some(unit_index) => {
|
||||||
|
let (value, unit) = v.split_at(unit_index);
|
||||||
|
let value: f64 = value.parse().map_err(Error::custom)?;
|
||||||
|
|
||||||
|
let multiple: u64 = match unit.trim_start() {
|
||||||
|
"KB" | "kB" => 1000,
|
||||||
|
"MB" => 1000 * 1000,
|
||||||
|
"GB" => 1000 * 1000 * 1000,
|
||||||
|
"TB" => 1000 * 1000 * 1000 * 1000,
|
||||||
|
|
||||||
|
"KiB" => 1024,
|
||||||
|
"MiB" => 1024 * 1024,
|
||||||
|
"GiB" => 1024 * 1024 * 1024,
|
||||||
|
"TiB" => 1024 * 1024 * 1024 * 1024,
|
||||||
|
|
||||||
|
unit => {
|
||||||
|
return Err(Error::invalid_value(
|
||||||
|
Unexpected::Str(unit),
|
||||||
|
&"known unit of measurement",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let value = value * (multiple as f64);
|
||||||
|
|
||||||
|
Ok(Some(value.round() as u64))
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
// No unit found, interpret as raw number
|
||||||
|
v.parse().map(Some).map_err(Error::custom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_none<E>(self) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: Error,
|
||||||
|
{
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
deserializer.deserialize_any(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use serde::de::value::Error;
|
||||||
|
use serde::de::IntoDeserializer;
|
||||||
|
|
||||||
|
use super::deserialize;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_deserialize() {
|
||||||
|
fn check_result(input: &str, value: u64) {
|
||||||
|
assert_eq!(
|
||||||
|
deserialize(input.into_deserializer()),
|
||||||
|
Ok::<_, Error>(Some(value))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
check_result("1234", 1234);
|
||||||
|
check_result("1234 ", 1234);
|
||||||
|
check_result(" 1234", 1234);
|
||||||
|
check_result(" 1234 ", 1234);
|
||||||
|
|
||||||
|
check_result("1234kB", 1234 * 1000);
|
||||||
|
check_result("1234KB", 1234 * 1000);
|
||||||
|
check_result("1234MB", 1234 * 1000 * 1000);
|
||||||
|
check_result("1234GB", 1234 * 1000 * 1000 * 1000);
|
||||||
|
check_result("1234TB", 1234 * 1000 * 1000 * 1000 * 1000);
|
||||||
|
|
||||||
|
check_result("1234KiB", 1234 * 1024);
|
||||||
|
check_result("1234MiB", 1234 * 1024 * 1024);
|
||||||
|
check_result("1234GiB", 1234 * 1024 * 1024 * 1024);
|
||||||
|
check_result("1234TiB", 1234 * 1024 * 1024 * 1024 * 1024);
|
||||||
|
|
||||||
|
check_result("1234 kB", 1234 * 1000);
|
||||||
|
check_result("1234 KB", 1234 * 1000);
|
||||||
|
check_result("1234 MB", 1234 * 1000 * 1000);
|
||||||
|
check_result("1234 GB", 1234 * 1000 * 1000 * 1000);
|
||||||
|
check_result("1234 TB", 1234 * 1000 * 1000 * 1000 * 1000);
|
||||||
|
|
||||||
|
check_result("1234 KiB", 1234 * 1024);
|
||||||
|
check_result("1234 MiB", 1234 * 1024 * 1024);
|
||||||
|
check_result("1234 GiB", 1234 * 1024 * 1024 * 1024);
|
||||||
|
check_result("1234 TiB", 1234 * 1024 * 1024 * 1024 * 1024);
|
||||||
|
}
|
||||||
|
}
|
@ -26,6 +26,7 @@ use serde::Deserialize;
|
|||||||
mod config;
|
mod config;
|
||||||
mod dump;
|
mod dump;
|
||||||
mod format;
|
mod format;
|
||||||
|
mod human_number;
|
||||||
mod log;
|
mod log;
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
@ -195,8 +196,11 @@ struct VgpuProfileOverride<'a> {
|
|||||||
multi_vgpu_supported: Option<u32>,
|
multi_vgpu_supported: Option<u32>,
|
||||||
pci_id: Option<u64>,
|
pci_id: Option<u64>,
|
||||||
pci_device_id: Option<u64>,
|
pci_device_id: Option<u64>,
|
||||||
|
#[serde(with = "human_number")]
|
||||||
framebuffer: Option<u64>,
|
framebuffer: Option<u64>,
|
||||||
|
#[serde(with = "human_number")]
|
||||||
mappable_video_size: Option<u64>,
|
mappable_video_size: Option<u64>,
|
||||||
|
#[serde(with = "human_number")]
|
||||||
framebuffer_reservation: Option<u64>,
|
framebuffer_reservation: Option<u64>,
|
||||||
encoder_capacity: Option<u64>,
|
encoder_capacity: Option<u64>,
|
||||||
bar1_length: Option<u64>,
|
bar1_length: Option<u64>,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user