1use crate::*;
26
27use std::{
28 fmt,
29 io::{BufRead, Error as ioError, Write},
30};
31
32use super::{types::*, utils::*};
33
34pub fn save_xyz<RA, P, W>(
38 write: &mut W,
39 ra: &RA,
40 delim_coord: &str,
41 delim_pos: &str,
42) -> XyzResult<()>
43where
44 RA: IsRandomAccessible<P>,
45 P: Is3D,
46 W: Write,
47{
48 let n = ra.len();
49 for i in 0..n {
50 let ref p = ra[i];
51 let buffer = p.x().to_string()
52 + delim_coord
53 + &p.y().to_string()
54 + delim_coord
55 + &p.z().to_string()
56 + delim_pos;
57 write.write_all(buffer.as_bytes())?;
58 }
59 Ok(())
60}
61
62pub fn load_xyz<IP, P, R>(read: &mut R, ip: &mut IP) -> XyzIOResult<()>
64where
65 IP: IsPushable<P>,
66 P: IsBuildable3D,
67 R: BufRead,
68{
69 let mut delim_determined = false;
70 let mut delim = 0;
71 let mut line_buffer = Vec::new();
72
73 let mut i_line = 0;
74
75 while let Ok(line) = fetch_line(read, &mut line_buffer) {
76 i_line += 1;
77
78 if !delim_determined {
79 delim = estimate_delimiter(2, &line)
80 .ok_or(XyzError::EstimateDelimiter)
81 .line(i_line, line)?;
82 delim_determined = true;
83 }
84
85 let mut words = line.split(|x| *x == delim).skip_empty();
86
87 let x = words
88 .next()
89 .and_then(|word| from_ascii(word))
90 .ok_or(XyzError::Vertex)
91 .line(i_line, line)?;
92
93 let y = words
94 .next()
95 .and_then(|word| from_ascii(word))
96 .ok_or(XyzError::Vertex)
97 .line(i_line, line)?;
98
99 let z = words
100 .next()
101 .and_then(|word| from_ascii(word))
102 .ok_or(XyzError::Vertex)
103 .line(i_line, line)?;
104
105 ip.push(P::new(x, y, z));
106 }
107
108 Ok(())
109}
110
111pub enum XyzError {
115 EstimateDelimiter,
116 AccessFile,
117 Vertex,
118}
119
120pub type XyzResult<T> = std::result::Result<T, XyzError>;
122
123pub type XyzIOResult<T> = IOResult<T, XyzError>;
125
126impl fmt::Debug for XyzError {
127 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
128 match self {
129 Self::Vertex => write!(f, "Unable to parse vertex"),
130 Self::AccessFile => write!(f, "Unable to access file"),
131 Self::EstimateDelimiter => write!(f, "Unable to estimate delimiter"),
132 }
133 }
134}
135
136impl fmt::Display for XyzError {
137 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
138 write!(f, "{:?}", self)
139 }
140}
141
142impl From<ioError> for XyzError {
143 fn from(_error: ioError) -> Self {
144 XyzError::AccessFile
145 }
146}