Skip to main content

vec3_rs/
convert.rs

1use crate::{Vector3, Vector3Coordinate};
2
3impl<T: Vector3Coordinate> From<(T, T, T)> for Vector3<T> {
4    fn from(value: (T, T, T)) -> Self {
5        Self {
6            x: value.0,
7            y: value.1,
8            z: value.2,
9        }
10    }
11}
12
13impl<T: Vector3Coordinate> From<Vector3<T>> for (T, T, T) {
14    fn from(value: Vector3<T>) -> Self {
15        (value.x, value.y, value.z)
16    }
17}
18
19impl<T: Vector3Coordinate> From<[T; 3]> for Vector3<T> {
20    fn from(value: [T; 3]) -> Self {
21        let [x, y, z] = value;
22        Self { x, y, z }
23    }
24}
25
26#[cfg(feature = "std")]
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(thiserror::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    #[error("invalid slice length: expected 3, got {0}")]
42    InvalidSlice(usize),
43}
44
45#[cfg(feature = "std")]
46impl<T: Vector3Coordinate> TryFrom<Vec<T>> for Vector3<T> {
47    type Error = ParseVector3Error;
48    fn try_from(value: Vec<T>) -> Result<Self, Self::Error> {
49        let array: [T; 3] = value
50            .try_into()
51            .map_err(|v: Vec<T>| ParseVector3Error::InvalidVec(v.len()))?;
52        Ok(Self::from(array))
53    }
54}
55
56#[cfg(feature = "std")]
57impl<T: Vector3Coordinate> TryFrom<std::collections::VecDeque<T>> for Vector3<T> {
58    type Error = ParseVector3Error;
59    fn try_from(mut value: std::collections::VecDeque<T>) -> Result<Self, Self::Error> {
60        let x = value
61            .pop_front()
62            .ok_or(ParseVector3Error::InvalidVec(value.len()))?;
63        let y = value
64            .pop_front()
65            .ok_or(ParseVector3Error::InvalidVec(value.len()))?;
66        let z = value
67            .pop_front()
68            .ok_or(ParseVector3Error::InvalidVec(value.len()))?;
69
70        Ok(Self::new(x, y, z))
71    }
72}
73
74impl<T: Vector3Coordinate> TryFrom<&[T]> for Vector3<T> {
75    type Error = ParseVector3Error;
76    fn try_from(value: &[T]) -> Result<Self, Self::Error> {
77        let array: &[T; 3] = value
78            .as_array()
79            .ok_or(ParseVector3Error::InvalidSlice(value.len()))?;
80
81        Ok(Self::from(array.clone()))
82    }
83}
84
85impl<T: Vector3Coordinate> TryFrom<Box<[T]>> for Vector3<T> {
86    type Error = ParseVector3Error;
87    fn try_from(value: Box<[T]>) -> Result<Self, Self::Error> {
88        let array: &[T; 3] = value
89            .as_array()
90            .ok_or(ParseVector3Error::InvalidSlice(value.len()))?;
91
92        Ok(Self::from(array.clone()))
93    }
94}
95
96impl<T> core::str::FromStr for Vector3<T>
97where
98    T: Vector3Coordinate + core::str::FromStr,
99{
100    type Err = ParseVector3Error;
101    fn from_str(s: &str) -> Result<Self, Self::Err> {
102        let Some(data) = s.strip_prefix("Vector3(") else {
103            return Err(ParseVector3Error::InvalidStringFormat);
104        };
105        let Some(data) = data.strip_suffix(")") else {
106            return Err(ParseVector3Error::InvalidStringFormat);
107        };
108
109        let mut components = data
110            .split(',')
111            .take(3)
112            .enumerate()
113            .flat_map(|(index, coord)| {
114                coord
115                    .trim()
116                    .parse::<T>()
117                    .map_err(|_| ParseVector3Error::StringParseComponentError(index + 1))
118            });
119
120        // dear rust, collect into array/tuple when?
121        // do i seriously need to pull itertools for this??
122        let x = components
123            .next()
124            .ok_or(ParseVector3Error::StringParseComponentError(1))?;
125        let y = components
126            .next()
127            .ok_or(ParseVector3Error::StringParseComponentError(2))?;
128        let z = components
129            .next()
130            .ok_or(ParseVector3Error::StringParseComponentError(3))?;
131
132        Ok(Self::new(x, y, z))
133    }
134}
135
136#[cfg(test)]
137mod test {
138    use super::*;
139
140    #[test]
141    fn vec_string() {
142        let v1: Vector3<i32> = Vector3::new(1, 2, 3);
143        let v2: Vector3<i32> = String::from("Vector3( 1,2,     3)").parse().unwrap();
144        assert_eq!(v1, v2);
145    }
146
147    #[test]
148    fn vec_str() {
149        let v1 = Vector3::new(1, 2, 3);
150        let v2 = "Vector3(1,  2 ,3 )".parse().unwrap();
151        assert_eq!(v1, v2);
152    }
153
154    #[test]
155    fn vec_tuple() {
156        let v1 = Vector3::new(1, 2, 3);
157        let v2 = (1, 2, 3).into();
158        assert_eq!(v1, v2);
159    }
160
161    #[test]
162    fn vec_array() {
163        let v1 = Vector3::new(1, 2, 3);
164        let v2 = [1, 2, 3].into();
165        assert_eq!(v1, v2);
166    }
167
168    #[test]
169    fn vec_vec() {
170        let v1 = Vector3::new(1, 2, 3);
171        let v2 = vec![1, 2, 3].try_into().unwrap();
172        assert_eq!(v1, v2);
173    }
174
175    #[test]
176    fn vec_deq() {
177        let v1 = Vector3::new(1, 2, 3);
178        let v2 = std::collections::VecDeque::from([1, 2, 3])
179            .try_into()
180            .unwrap();
181        assert_eq!(v1, v2);
182    }
183}