nu_protocol/config/
filesize.rs

1use super::prelude::*;
2use crate::{Filesize, FilesizeFormatter, FilesizeUnitFormat, FormattedFilesize};
3use nu_utils::get_system_locale;
4
5impl IntoValue for FilesizeUnitFormat {
6    fn into_value(self, span: Span) -> Value {
7        self.as_str().into_value(span)
8    }
9}
10
11#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
12pub struct FilesizeConfig {
13    pub unit: FilesizeUnitFormat,
14    pub show_unit: bool,
15    pub precision: Option<usize>,
16}
17
18impl FilesizeConfig {
19    pub fn formatter(&self) -> FilesizeFormatter {
20        FilesizeFormatter::new()
21            .unit(self.unit)
22            .show_unit(self.show_unit)
23            .precision(self.precision)
24            .locale(get_system_locale()) // TODO: cache this somewhere or pass in as argument
25    }
26
27    pub fn format(&self, filesize: Filesize) -> FormattedFilesize {
28        self.formatter().format(filesize)
29    }
30}
31
32impl Default for FilesizeConfig {
33    fn default() -> Self {
34        Self {
35            unit: FilesizeUnitFormat::Metric,
36            show_unit: true,
37            precision: Some(1),
38        }
39    }
40}
41
42impl From<FilesizeConfig> for FilesizeFormatter {
43    fn from(config: FilesizeConfig) -> Self {
44        config.formatter()
45    }
46}
47
48impl UpdateFromValue for FilesizeConfig {
49    fn update<'a>(
50        &mut self,
51        value: &'a Value,
52        path: &mut ConfigPath<'a>,
53        errors: &mut ConfigErrors,
54    ) {
55        let Value::Record { val: record, .. } = value else {
56            errors.type_mismatch(path, Type::record(), value);
57            return;
58        };
59
60        for (col, val) in record.iter() {
61            let path = &mut path.push(col);
62            match col.as_str() {
63                "unit" => {
64                    if let Ok(str) = val.as_str() {
65                        match str.parse() {
66                            Ok(unit) => self.unit = unit,
67                            Err(_) => errors.invalid_value(path, "'metric', 'binary', 'B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', or 'EiB'", val),
68                        }
69                    } else {
70                        errors.type_mismatch(path, Type::String, val)
71                    }
72                }
73                "show_unit" => self.show_unit.update(val, path, errors),
74                "precision" => match *val {
75                    Value::Nothing { .. } => self.precision = None,
76                    Value::Int { val, .. } if val >= 0 => self.precision = Some(val as usize),
77                    Value::Int { .. } => errors.invalid_value(path, "a non-negative integer", val),
78                    _ => errors.type_mismatch(path, Type::custom("int or nothing"), val),
79                },
80                _ => errors.unknown_option(path, val),
81            }
82        }
83    }
84}
85
86impl IntoValue for FilesizeConfig {
87    fn into_value(self, span: Span) -> Value {
88        record! {
89            "unit" => self.unit.into_value(span),
90            "show_unit" => self.show_unit.into_value(span),
91            "precision" => self.precision.map(|x| x as i64).into_value(span),
92        }
93        .into_value(span)
94    }
95}