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}