Skip to main content

malachite_q/rational_vector/conversion/string/
from_string.rs

1// Copyright © 2026 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::Rational;
10use crate::rational_vector::RationalVector;
11use alloc::vec::Vec;
12use core::str::FromStr;
13
14impl FromStr for RationalVector {
15    type Err = ();
16
17    /// Converts a string to a [`RationalVector`].
18    ///
19    /// This reads back what [`Display`](core::fmt::Display) writes: the elements in order,
20    /// separated by `", "` and enclosed in parentheses, with `()` for the 0-dimensional vector.
21    /// Each element is read the way [`Rational::from_str`] reads one, so it need not be in lowest
22    /// terms, and may have leading zeros and a single leading `'-'` or `'+'`. Any other spacing,
23    /// such as `(1,2)` or `( 1, 2 )`, is rejected, as is an empty element.
24    ///
25    /// If the string does not represent a [`RationalVector`], an `Err` is returned.
26    ///
27    /// # Worst-case complexity
28    /// $T(n) = O(n (\log n)^2 \log\log n)$
29    ///
30    /// $M(n) = O(n \log n)$
31    ///
32    /// where $T$ is time, $M$ is additional memory, and $n$ is `s.len()`.
33    ///
34    /// # Examples
35    /// ```
36    /// use core::str::FromStr;
37    /// use malachite_base::vector::Vector;
38    /// use malachite_q::rational_vector::RationalVector;
39    ///
40    /// assert_eq!(
41    ///     RationalVector::from_str("(1, 2, 3)").unwrap().to_string(),
42    ///     "(1, 2, 3)"
43    /// );
44    /// assert_eq!(RationalVector::from_str("(5)").unwrap().to_string(), "(5)");
45    /// assert_eq!(RationalVector::from_str("()").unwrap().dimension(), 0);
46    ///
47    /// // An element may be written as `Rational::from_str` accepts it.
48    /// assert_eq!(
49    ///     RationalVector::from_str("(-1, 2/4, +6/3)")
50    ///         .unwrap()
51    ///         .to_string(),
52    ///     "(-1, 1/2, 2)"
53    /// );
54    /// assert_eq!(
55    ///     RationalVector::from_str("(007, +8)").unwrap().to_string(),
56    ///     "(7, 8)"
57    /// );
58    ///
59    /// assert!(RationalVector::from_str("").is_err());
60    /// assert!(RationalVector::from_str("1, 2").is_err());
61    /// assert!(RationalVector::from_str("(1,2)").is_err());
62    /// assert!(RationalVector::from_str("( 1, 2 )").is_err());
63    /// assert!(RationalVector::from_str("(1, )").is_err());
64    /// assert!(RationalVector::from_str("(--1)").is_err());
65    /// assert!(RationalVector::from_str("(1/0)").is_err());
66    /// ```
67    fn from_str(s: &str) -> Result<Self, ()> {
68        let inner = s
69            .strip_prefix('(')
70            .and_then(|s| s.strip_suffix(')'))
71            .ok_or(())?;
72        if inner.is_empty() {
73            return Ok(Self {
74                elements: Vec::new(),
75            });
76        }
77        Ok(Self {
78            elements: inner
79                .split(", ")
80                .map(Rational::from_str)
81                .collect::<Result<_, _>>()?,
82        })
83    }
84}