Skip to main content

ferroui_dialogs/internal/
file_size_string_converter.rs

1use ferroui_base::utilities::CultureInfo;
2use ferroui_base::data::converters::IValueConverter;
3use ferroui_base::data::core::ValueType;
4use ferroui_base::data::BindingError;
5use ferroui_base::utilities::ByteSizeHelper;
6use ferroui_base::{ferro_markup_type, BoxedValue};
7use std::rc::Rc;
8
9/// Converts a size in bytes to text with a unit (`1.5KB`); a size that is
10/// not positive converts to empty text.
11#[derive(Default)]
12pub struct FileSizeStringConverter;
13
14impl PartialEq for FileSizeStringConverter {
15    fn eq(&self, other: &Self) -> bool {
16        std::ptr::eq(self, other)
17    }
18}
19
20impl FileSizeStringConverter {
21    pub fn new() -> Rc<Self> {
22        Rc::new(Self)
23    }
24}
25
26impl IValueConverter for FileSizeStringConverter {
27    fn convert(
28        &self,
29        value: Option<&BoxedValue>,
30        _target_type: ValueType,
31        _parameter: Option<&BoxedValue>,
32        _culture: &CultureInfo,
33    ) -> Result<Option<BoxedValue>, BindingError> {
34        if let Some(&size) = value.and_then(|value| value.downcast_ref::<i64>()) {
35            if size > 0 {
36                return Ok(Some(Rc::new(ByteSizeHelper::to_string(size as u64, true))));
37            }
38        }
39
40        Ok(Some(Rc::new(String::new())))
41    }
42
43    /// Fails: the conversion has no inverse.
44    fn convert_back(
45        &self,
46        _value: Option<&BoxedValue>,
47        _target_type: ValueType,
48        _parameter: Option<&BoxedValue>,
49        _culture: &CultureInfo,
50    ) -> Result<Option<BoxedValue>, BindingError> {
51        Err(BindingError::message("The method or operation is not implemented."))
52    }
53}
54
55ferro_markup_type!(class FileSizeStringConverter {
56    this: Rc<FileSizeStringConverter>,
57    handles: [FileSizeStringConverter, Rc<FileSizeStringConverter>, Option<Rc<FileSizeStringConverter>>],
58    interfaces: [Rc<dyn IValueConverter>],
59    constructors: [() => FileSizeStringConverter::new],
60});
61
62#[cfg(test)]
63mod tests {
64    // Not from upstream: the upstream project has no tests.
65    use super::*;
66
67    fn convert(value: BoxedValue) -> String {
68        let converted = FileSizeStringConverter::new().convert(Some(&value), ValueType::of::<String>(), None, &ferroui_base::utilities::CultureInfo::invariant_culture()).unwrap();
69        converted.unwrap().downcast_ref::<String>().cloned().unwrap()
70    }
71
72    #[test]
73    fn converts_positive_sizes_and_nothing_else() {
74        assert_eq!("1.5KB", convert(Rc::new(1500i64)));
75        assert_eq!("", convert(Rc::new(0i64)));
76        assert_eq!("", convert(Rc::new(-5i64)));
77        // Only a 64-bit size is a size.
78        assert_eq!("", convert(Rc::new(1500i32)));
79    }
80}