Skip to main content

vec3_rs/
convert.rs

1use crate::{Vector3, Vector3Coordinate};
2use thiserror::Error;
3
4impl<T: Vector3Coordinate> From<(T, T, T)> for Vector3<T> {
5    fn from(value: (T, T, T)) -> Self {
6        Self {
7            x: value.0,
8            y: value.1,
9            z: value.2,
10        }
11    }
12}
13
14impl<T: Vector3Coordinate> From<Vector3<T>> for (T, T, T) {
15    fn from(value: Vector3<T>) -> Self {
16        (value.x, value.y, value.z)
17    }
18}
19
20impl<T: Vector3Coordinate> From<[T; 3]> for Vector3<T> {
21    fn from(value: [T; 3]) -> Self {
22        let [x, y, z] = value;
23        Self { x, y, z }
24    }
25}
26
27impl<T: Vector3Coordinate> From<Vector3<T>> for [T; 3] {
28    fn from(value: Vector3<T>) -> Self {
29        [value.x, value.y, value.z]
30    }
31}
32
33#[derive(Error, Debug)]
34pub enum ParseVector3Error {
35    #[error("failed to parse #{0}th component")]
36    StringParseComponentError(usize),
37    #[error("invalid format")]
38    InvalidStringFormat,
39    #[error("invalid vector length: expected 3, got {0}")]
40    InvalidVec(usize),
41}
42
43impl<T: Vector3Coordinate> TryFrom<Vec<T>> for Vector3<T> {
44    type Error = ParseVector3Error;
45    fn try_from(value: Vec<T>) -> Result<Self, Self::Error> {
46        let array: [T; 3] = value
47            .try_into()
48            .map_err(|v: Vec<T>| ParseVector3Error::InvalidVec(v.len()))?;
49        Ok(Self::from(array))
50    }
51}
52
53impl<T: Vector3Coordinate> TryFrom<std::collections::VecDeque<T>> for Vector3<T> {
54    type Error = ParseVector3Error;
55    fn try_from(mut value: std::collections::VecDeque<T>) -> Result<Self, Self::Error> {
56        let x = value
57            .pop_front()
58            .ok_or(ParseVector3Error::InvalidVec(value.len()))?;
59        let y = value
60            .pop_front()
61            .ok_or(ParseVector3Error::InvalidVec(value.len()))?;
62        let z = value
63            .pop_front()
64            .ok_or(ParseVector3Error::InvalidVec(value.len()))?;
65        Ok(Self::new(x, y, z))
66    }
67}
68
69impl<T> std::str::FromStr for Vector3<T>
70where
71    T: Vector3Coordinate + std::str::FromStr,
72{
73    type Err = ParseVector3Error;
74    fn from_str(s: &str) -> Result<Self, Self::Err> {
75        let Some(data) = s.strip_prefix("Vector3(") else {
76            return Err(ParseVector3Error::InvalidStringFormat);
77        };
78        let Some(data) = data.strip_suffix(")") else {
79            return Err(ParseVector3Error::InvalidStringFormat);
80        };
81
82        let components: Result<Vec<T>, ParseVector3Error> = data
83            .split(',')
84            .take(3)
85            .enumerate()
86            .map(|(index, coord)| {
87                coord
88                    .trim()
89                    .parse::<T>()
90                    .map_err(|_| ParseVector3Error::StringParseComponentError(index + 1))
91            })
92            .collect();
93
94        let components = components?;
95        components.try_into()
96    }
97}
98
99#[cfg(test)]
100mod test {
101    use super::*;
102
103    #[test]
104    fn vec_string() {
105        let v1: Vector3<i32> = Vector3::new(1, 2, 3);
106        let v2: Vector3<i32> = String::from("Vector3( 1,2,     3)").parse().unwrap();
107        assert_eq!(v1, v2);
108    }
109
110    #[test]
111    fn vec_str() {
112        let v1 = Vector3::new(1, 2, 3);
113        let v2 = "Vector3(1,  2 ,3 )".parse().unwrap();
114        assert_eq!(v1, v2);
115    }
116
117    #[test]
118    fn vec_tuple() {
119        let v1 = Vector3::new(1, 2, 3);
120        let v2 = (1, 2, 3).into();
121        assert_eq!(v1, v2);
122    }
123
124    #[test]
125    fn vec_array() {
126        let v1 = Vector3::new(1, 2, 3);
127        let v2 = [1, 2, 3].into();
128        assert_eq!(v1, v2);
129    }
130
131    #[test]
132    fn vec_vec() {
133        let v1 = Vector3::new(1, 2, 3);
134        let v2 = vec![1, 2, 3].try_into().unwrap();
135        assert_eq!(v1, v2);
136    }
137
138    #[test]
139    fn vec_deq() {
140        let v1 = Vector3::new(1, 2, 3);
141        let v2 = std::collections::VecDeque::from([1, 2, 3])
142            .try_into()
143            .unwrap();
144        assert_eq!(v1, v2);
145    }
146}