awint_ext/awi_struct/
strings.rs

1use alloc::{string::String, vec::Vec};
2use core::num::NonZeroUsize;
3
4use awint_core::{Bits, SerdeError};
5
6use crate::{
7    string_internals::{
8        bits_to_string_radix, bits_to_vec_radix, internal_from_bytes_general,
9        internal_from_bytes_radix, internal_from_str,
10    },
11    Awi,
12};
13
14/// # non-`const` string representation conversion
15impl Awi {
16    /// Creates a `Vec<u8>` representing `bits` (sign indicators, prefixes, and
17    /// postfixes not included). This function performs allocation. This is
18    /// a wrapper around [awint_core::Bits::to_bytes_radix] that truncates
19    /// leading zeros. An additional `min_chars` specifies the minimum
20    /// number of characters that should exist. `min_chars` specifies the
21    /// minimum number of chars in the integer part, inserting leading '0's if
22    /// there are not enough chars, just like Rust's built in `{:0d}`
23    /// formatting. Note that an empty vector will be returned if
24    /// `min_chars == 0 && bits.is_zero()`.
25    ///
26    /// # Errors
27    ///
28    /// This can only return an error if `radix` is not in the range 2..=36 or
29    /// if resource exhaustion occurs.
30    pub fn bits_to_vec_radix(
31        bits: &Bits,
32        signed: bool,
33        radix: u8,
34        upper: bool,
35        min_chars: usize,
36    ) -> Result<Vec<u8>, SerdeError> {
37        bits_to_vec_radix(bits, signed, radix, upper, min_chars)
38    }
39
40    /// Creates a string representing `bits`. This function performs allocation.
41    /// This does the same thing as [Awi::bits_to_vec_radix] but with a
42    /// `String`.
43    pub fn bits_to_string_radix(
44        bits: &Bits,
45        signed: bool,
46        radix: u8,
47        upper: bool,
48        min_chars: usize,
49    ) -> Result<String, SerdeError> {
50        bits_to_string_radix(bits, signed, radix, upper, min_chars)
51    }
52
53    /// Creates an `Awi` representing the given arguments. This function
54    /// performs allocation. This is a wrapper around
55    /// [awint_core::Bits::bytes_radix_] that zero or sign resizes the
56    /// result to match `bw`.
57    ///
58    /// # Errors
59    ///
60    /// See the error conditions of [Bits::bytes_radix_]. Note that `-` is
61    /// an invalid character even though `to_vec_radix` can return `-`. This
62    /// is because we need to handle both unsigned and signed integer
63    /// inputs, specified only by `sign`. If the input is a negative signed
64    /// integer representation with `-` appended to the front, the subslice
65    /// `src[1..]` can be taken and `sign` can be set to `Some(true)`.
66    pub fn from_bytes_radix(
67        sign: Option<bool>,
68        src: &[u8],
69        radix: u8,
70        bw: NonZeroUsize,
71    ) -> Result<Awi, SerdeError> {
72        let mut res = Awi::zero(bw);
73        internal_from_bytes_radix(&mut res, sign, src, radix)?;
74        Ok(res)
75    }
76
77    /// Creates an `Awi` representing the given arguments. This does the same
78    /// thing as [Awi::from_bytes_radix] but with an `&str`.
79    pub fn from_str_radix(
80        sign: Option<bool>,
81        str: &str,
82        radix: u8,
83        bw: NonZeroUsize,
84    ) -> Result<Awi, SerdeError> {
85        let mut res = Awi::zero(bw);
86        internal_from_bytes_radix(&mut res, sign, str.as_bytes(), radix)?;
87        Ok(res)
88    }
89
90    /// Creates an `Awi` representing the given arguments. This function
91    /// performs allocation. In addition to the arguments and semantics from
92    /// [Awi::from_bytes_radix], this function includes the ability to deal
93    /// with general fixed point integer deserialization. `src` is now split
94    /// into separate `integer` and `fraction` parts. An exponent `exp` further
95    /// multiplies the numerical value by `radix^exp`. `fp` is the location
96    /// of the fixed point in the output representation of the numerical
97    /// value (e.x. for a plain integer `fp == 0`). `fp` can be negative or
98    /// greater than the bitwidth.
99    ///
100    /// This function uses a single rigorous round-to-even that occurs after
101    /// the exponent and fixed point multiplier are applied and before any
102    /// numerical information is lost.
103    ///
104    /// See [crate::FP::to_vec_general] for the inverse of this function.
105    ///
106    /// # Errors
107    ///
108    /// See the error conditions of [Awi::from_bytes_radix]. The precision
109    /// can now be arbitrarily large (any overflow in the low numerical
110    /// significance direction will be rounded), but overflow can still happen
111    /// in the more significant direction. Empty strings are interpreted as a
112    /// zero value.
113    pub fn from_bytes_general(
114        sign: Option<bool>,
115        integer: &[u8],
116        fraction: &[u8],
117        exp: isize,
118        radix: u8,
119        bw: NonZeroUsize,
120        fp: isize,
121    ) -> Result<Awi, SerdeError> {
122        let mut res = Awi::zero(bw);
123        internal_from_bytes_general(&mut res, sign, integer, fraction, exp, radix, fp)?;
124        Ok(res)
125    }
126
127    /// Creates an `Awi` representing the given arguments. This does the same
128    /// thing as [Awi::from_bytes_general] but with `&str`s.
129    pub fn from_str_general(
130        sign: Option<bool>,
131        integer: &str,
132        fraction: &str,
133        exp: isize,
134        radix: u8,
135        bw: NonZeroUsize,
136        fp: isize,
137    ) -> Result<Awi, SerdeError> {
138        let mut res = Awi::zero(bw);
139        internal_from_bytes_general(
140            &mut res,
141            sign,
142            integer.as_bytes(),
143            fraction.as_bytes(),
144            exp,
145            radix,
146            fp,
147        )?;
148        Ok(res)
149    }
150}
151
152impl core::str::FromStr for Awi {
153    type Err = SerdeError;
154
155    /// Creates an `Awi` described by `s`. There are three modes of operation
156    /// which invoke [Awi::from_str_radix] or [Awi::from_str_general]
157    /// differently.
158    ///
159    /// Note: there is currently a
160    /// [bug](https://github.com/rust-lang/rust/issues/108385) in Rust that
161    /// causes certain fixed point literals to fail to parse when attempting
162    /// to use them in the concatenation macros. In case of getting
163    /// "literal is not supported" errors, use `Awi::from_str` directly.
164    ///
165    /// Additionally, note that it is easy to cause resource exhaustion with
166    /// large bitwidths, exponents, or fixed points that can approach
167    /// `usize::MAX`. In a future version of `awint` we should have a guarded
168    /// function for helping with entering literals through things like UIs.
169    ///
170    /// All valid inputs must begin with '0'-'9' or a '-' followed by '0'-'9'.
171    ///
172    /// If only ' _ ', '0', and '1' chars are present, this function uses binary
173    /// mode. It will interpret the input as a binary string, the number of '0's
174    /// and '1's of which is the bitwidth (including leading '0's and excluding
175    /// ' _ 's). For example: 42 in binary is 101010. If "101010" is entered
176    /// into this function, it will return an `ExtAwi` with bitwidth 6 and
177    /// unsigned value 42. "0000101010" results in bitwidth 10 and unsigned
178    /// value 42. "1111_1111" results in bitwidth 8 and signed value -128 or
179    /// equivalently unsigned value 255.
180    ///
181    /// In integer mode, a decimal bitwidth must be specified after a 'u'
182    /// (unsigned) or 'i' (signed) suffix. A prefix of "0b" specifies a binary
183    /// radix, "0o" specifies an octal radix, "0x" specifies hexadecimal,
184    /// otherwise a decimal radix is used. For example: "42u10" entered into
185    /// this function creates an `ExtAwi` with bitwidth 10 and unsigned
186    /// value 42. "-42i10" results in bitwidth 10 and signed value of -42.
187    /// "0xffff_ffffu32" results in bitwidth 32 and an unsigned value of
188    /// 0xffffffff (also 4294967295 in decimal and u32::MAX).
189    /// "0x1_0000_0000u32" results in an error with `SerdeError::Overflow`,
190    /// because it exceeds the maximum unsigned value for a 32 bit integer.
191    /// "123" results in `SerdeError::EmptyBitwidth`, because it is not in
192    /// binary mode and no bitwidth suffix has been supplied.
193    ///
194    /// If, after the bitwidth, an 'f' char is present, fixed point mode is
195    /// activated. A decimal fixed point position must be specified after the
196    /// 'f' that tells where the fixed point will be in the resulting bits (see
197    /// [crate::FP] for more). If the most significant numerical bit would be
198    /// cut off, `SerdeError::Overflow` is returned.
199    ///
200    /// Additionally, an exponent char 'e' (for non-hexadecimal radixes only) or
201    /// 'p' can be included after the integer or fraction parts but before the
202    /// bitwidth suffix. The exponent as typed uses the radix of the integer
203    /// part, and it is raised to the same radix when modifying the numerical
204    /// value. The exponent can only be negative for fixed point mode. For
205    /// example: "123e5u32" has numerical value 12300000. "123e-5u32" returns an
206    /// error since it is trying to use a negative exponent in integer mode.
207    /// "-0x1234.5678p-3i32f16" has a numerical value of -0x1234.5678 *
208    /// 0x10^-0x3 and uses [Awi::from_bytes_general] to round-to-even to a 32
209    /// bit fixed point number with fixed point position 16. You probably want
210    /// to use underscores to make it clearer where different parts are, e.x.
211    /// "-0x1234.5678_p-3_i32_f16".
212    ///
213    /// For all parts including the integer, fraction, exponent, bitwidth, and
214    /// fixed point parts, if their prefix char exists but there is not at least
215    /// one '0' for them, some kind of empty error is returned. For example:
216    /// "0xu8" should be "0x0u8". ".i8f0" should be "0.0i8f0". "1u32f" should be
217    /// "1u32f0".
218    fn from_str(s: &str) -> Result<Self, Self::Err> {
219        internal_from_str(s, Awi::zero)
220    }
221}