toml_writer/
integer.rs

1use core::fmt::{self, Display};
2
3/// Describes how a TOML integer should be formatted.
4///
5/// # Example
6///
7/// ```rust
8/// # #[cfg(feature = "alloc")] {
9/// # use toml_writer::ToTomlValue as _;
10/// let format = toml_writer::TomlIntegerFormat::new().as_hex_lower();
11/// let number = 10;
12/// let number = format.format(number).unwrap_or(toml_writer::TomlInteger::new(number));
13/// let number = number.to_toml_value();
14/// assert_eq!(number, "0xa");
15/// # }
16/// ```
17#[derive(Copy, Clone, Debug)]
18pub struct TomlIntegerFormat {
19    radix: Radix,
20}
21
22impl TomlIntegerFormat {
23    /// Creates a new integer format (decimal).
24    pub fn new() -> Self {
25        Self {
26            radix: Radix::Decimal,
27        }
28    }
29
30    /// Sets the format to decimal.
31    pub fn as_decimal(mut self) -> Self {
32        self.radix = Radix::Decimal;
33        self
34    }
35
36    /// Sets the format to hexadecimal with all characters in uppercase.
37    pub fn as_hex_upper(mut self) -> Self {
38        self.radix = Radix::Hexadecimal {
39            case: HexCase::Upper,
40        };
41        self
42    }
43
44    /// Sets the format to hexadecimal with all characters in lowercase.
45    pub fn as_hex_lower(mut self) -> Self {
46        self.radix = Radix::Hexadecimal {
47            case: HexCase::Lower,
48        };
49        self
50    }
51
52    /// Sets the format to octal.
53    pub fn as_octal(mut self) -> Self {
54        self.radix = Radix::Octal;
55        self
56    }
57
58    /// Sets the format to binary.
59    pub fn as_binary(mut self) -> Self {
60        self.radix = Radix::Binary;
61        self
62    }
63
64    /// Formats `value` as a TOML integer.
65    ///
66    /// Returns `None` if the value cannot be formatted
67    /// (e.g. value is negative and the radix is not decimal).
68    pub fn format<N: PartialOrd<i32>>(self, value: N) -> Option<TomlInteger<N>>
69    where
70        TomlInteger<N>: crate::WriteTomlValue,
71    {
72        match self.radix {
73            Radix::Decimal => (),
74            Radix::Hexadecimal { .. } | Radix::Octal | Radix::Binary => {
75                if value < 0 {
76                    return None;
77                }
78            }
79        }
80
81        Some(TomlInteger {
82            value,
83            format: self,
84        })
85    }
86}
87
88impl Default for TomlIntegerFormat {
89    fn default() -> Self {
90        Self::new()
91    }
92}
93
94/// Helper struct for formatting TOML integers.
95///
96/// This may be constructed by calling [`TomlIntegerFormat::format()`].
97#[derive(Copy, Clone, Debug)]
98pub struct TomlInteger<N> {
99    value: N,
100    format: TomlIntegerFormat,
101}
102
103impl<N> TomlInteger<N>
104where
105    Self: crate::WriteTomlValue,
106{
107    /// Apply default formatting
108    pub fn new(value: N) -> Self {
109        Self {
110            value,
111            format: TomlIntegerFormat::new(),
112        }
113    }
114}
115
116impl crate::WriteTomlValue for TomlInteger<u8> {
117    fn write_toml_value<W: crate::TomlWrite + ?Sized>(&self, writer: &mut W) -> fmt::Result {
118        write_toml_value(self.value, &self.format, writer)
119    }
120}
121
122impl crate::WriteTomlValue for TomlInteger<i8> {
123    fn write_toml_value<W: crate::TomlWrite + ?Sized>(&self, writer: &mut W) -> fmt::Result {
124        write_toml_value(self.value, &self.format, writer)
125    }
126}
127
128impl crate::WriteTomlValue for TomlInteger<u16> {
129    fn write_toml_value<W: crate::TomlWrite + ?Sized>(&self, writer: &mut W) -> fmt::Result {
130        write_toml_value(self.value, &self.format, writer)
131    }
132}
133
134impl crate::WriteTomlValue for TomlInteger<i16> {
135    fn write_toml_value<W: crate::TomlWrite + ?Sized>(&self, writer: &mut W) -> fmt::Result {
136        write_toml_value(self.value, &self.format, writer)
137    }
138}
139
140impl crate::WriteTomlValue for TomlInteger<u32> {
141    fn write_toml_value<W: crate::TomlWrite + ?Sized>(&self, writer: &mut W) -> fmt::Result {
142        write_toml_value(self.value, &self.format, writer)
143    }
144}
145
146impl crate::WriteTomlValue for TomlInteger<i32> {
147    fn write_toml_value<W: crate::TomlWrite + ?Sized>(&self, writer: &mut W) -> fmt::Result {
148        write_toml_value(self.value, &self.format, writer)
149    }
150}
151
152impl crate::WriteTomlValue for TomlInteger<u64> {
153    fn write_toml_value<W: crate::TomlWrite + ?Sized>(&self, writer: &mut W) -> fmt::Result {
154        write_toml_value(self.value, &self.format, writer)
155    }
156}
157
158impl crate::WriteTomlValue for TomlInteger<i64> {
159    fn write_toml_value<W: crate::TomlWrite + ?Sized>(&self, writer: &mut W) -> fmt::Result {
160        write_toml_value(self.value, &self.format, writer)
161    }
162}
163
164impl crate::WriteTomlValue for TomlInteger<u128> {
165    fn write_toml_value<W: crate::TomlWrite + ?Sized>(&self, writer: &mut W) -> fmt::Result {
166        write_toml_value(self.value, &self.format, writer)
167    }
168}
169
170impl crate::WriteTomlValue for TomlInteger<i128> {
171    fn write_toml_value<W: crate::TomlWrite + ?Sized>(&self, writer: &mut W) -> fmt::Result {
172        write_toml_value(self.value, &self.format, writer)
173    }
174}
175
176impl crate::WriteTomlValue for TomlInteger<usize> {
177    fn write_toml_value<W: crate::TomlWrite + ?Sized>(&self, writer: &mut W) -> fmt::Result {
178        write_toml_value(self.value, &self.format, writer)
179    }
180}
181
182impl crate::WriteTomlValue for TomlInteger<isize> {
183    fn write_toml_value<W: crate::TomlWrite + ?Sized>(&self, writer: &mut W) -> fmt::Result {
184        write_toml_value(self.value, &self.format, writer)
185    }
186}
187
188#[derive(Copy, Clone, Debug)]
189enum Radix {
190    Decimal,
191    Hexadecimal { case: HexCase },
192    Octal,
193    Binary,
194}
195
196#[derive(Copy, Clone, Debug)]
197enum HexCase {
198    Upper,
199    Lower,
200}
201
202fn write_toml_value<
203    N: Display + fmt::UpperHex + fmt::LowerHex + fmt::Octal + fmt::Binary,
204    W: crate::TomlWrite + ?Sized,
205>(
206    value: N,
207    format: &TomlIntegerFormat,
208    writer: &mut W,
209) -> fmt::Result {
210    match format.radix {
211        Radix::Decimal => write!(writer, "{value}")?,
212        Radix::Hexadecimal { case } => match case {
213            HexCase::Upper => write!(writer, "0x{value:X}")?,
214            HexCase::Lower => write!(writer, "0x{value:x}")?,
215        },
216        Radix::Octal => write!(writer, "0o{value:o}")?,
217        Radix::Binary => write!(writer, "0b{value:b}")?,
218    }
219    Ok(())
220}