deep_time/time_parts/
from_str_ccsds.rs1use crate::{DtErr, DtErrKind, Scale, TimeParts, an_err};
2
3impl TimeParts {
4 pub fn from_str_ccsds(input: &str) -> Result<Self, DtErr> {
12 let bytes = input.as_bytes();
13 let len_ = bytes.len();
14
15 let mut start = 0usize;
16 while start < len_ {
17 let b = bytes[start];
18 if b.is_ascii_digit()
19 || (matches!(b, b'+' | b'-')
20 && start + 1 < len_
21 && bytes[start + 1].is_ascii_digit())
22 {
23 break;
24 }
25 start += 1;
26 }
27
28 if start == len_ {
29 return Err(an_err!(
30 DtErrKind::ExpectedValue,
31 "year start (digit or +/- and digit)"
32 ));
33 }
34
35 let input = &input[start..];
36 let bytes = input.as_bytes();
37 let len_ = bytes.len();
38 let mut fmt_buf: [u8; 128] = [0; 128];
39 let mut fmt_len: usize = 0;
40 let mut pos: usize = 0;
41
42 if pos < len_ && matches!(bytes[pos], b'+' | b'-') {
44 pos += 1;
45 }
46 let year_start = pos;
47 while pos < len_ && bytes[pos].is_ascii_digit() {
48 pos += 1;
49 }
50 let year_len = pos - year_start;
51 if year_len == 0 {
52 return Err(an_err!(
53 DtErrKind::ExpectedValue,
54 "year (digits after optional sign)"
55 ));
56 }
57 fmt_buf[fmt_len..fmt_len + 2].copy_from_slice(b"%*");
58 fmt_len += 2;
59
60 if pos < len_ && !bytes[pos].is_ascii_digit() {
62 fmt_buf[fmt_len] = bytes[pos];
63 fmt_len += 1;
64 pos += 1;
65 }
66
67 let is_doy = pos + 3 == len_ || pos + 3 < len_ && !bytes[pos + 3].is_ascii_digit();
69
70 if is_doy {
71 fmt_buf[fmt_len..fmt_len + 2].copy_from_slice(b"%j");
72 fmt_len += 2;
73 pos += 3;
74 } else {
75 if pos + 2 > len_ || !bytes[pos..pos + 2].iter().all(|&b| b.is_ascii_digit()) {
77 return Err(an_err!(DtErrKind::ExpectedValue, "2-digit month"));
78 }
79 fmt_buf[fmt_len..fmt_len + 2].copy_from_slice(b"%m");
80 fmt_len += 2;
81 pos += 2;
82
83 if pos < len_ && !bytes[pos].is_ascii_digit() {
84 fmt_buf[fmt_len] = bytes[pos];
85 fmt_len += 1;
86 pos += 1;
87 }
88
89 if pos + 2 > len_ || !bytes[pos..pos + 2].iter().all(|&b| b.is_ascii_digit()) {
91 return Err(an_err!(DtErrKind::ExpectedValue, "2-digit day"));
92 }
93 fmt_buf[fmt_len..fmt_len + 2].copy_from_slice(b"%d");
94 fmt_len += 2;
95 pos += 2;
96 }
97
98 if pos < len_ {
100 let c = bytes[pos];
101 if !c.is_ascii_digit() {
102 if pos + 1 < len_ && bytes[pos + 1].is_ascii_digit() {
104 fmt_buf[fmt_len] = c;
105 fmt_len += 1;
106 pos += 1;
107 }
108 } else {
109 return Err(an_err!(
110 DtErrKind::InvalidSyntax,
111 "expected time separator e.g. T"
112 ));
113 }
114 }
115
116 if pos < len_ && bytes[pos].is_ascii_digit() {
118 if pos + 2 <= len_ {
119 if !bytes[pos..pos + 2].iter().all(|&b| b.is_ascii_digit()) {
120 return Err(an_err!(DtErrKind::ExpectedValue, "2-digit hour"));
121 }
122 fmt_buf[fmt_len..fmt_len + 2].copy_from_slice(b"%H");
123 fmt_len += 2;
124 pos += 2;
125 }
126
127 if pos < len_ && !bytes[pos].is_ascii_digit() {
128 fmt_buf[fmt_len] = bytes[pos];
129 fmt_len += 1;
130 pos += 1;
131 }
132
133 if pos + 2 <= len_ {
134 if !bytes[pos..pos + 2].iter().all(|&b| b.is_ascii_digit()) {
135 return Err(an_err!(DtErrKind::ExpectedValue, "2-digit minute"));
136 }
137 fmt_buf[fmt_len..fmt_len + 2].copy_from_slice(b"%M");
138 fmt_len += 2;
139 pos += 2;
140 }
141
142 if pos < len_ && !bytes[pos].is_ascii_digit() {
143 fmt_buf[fmt_len] = bytes[pos];
144 fmt_len += 1;
145 pos += 1;
146 }
147
148 if pos + 2 <= len_ {
149 if !bytes[pos..pos + 2].iter().all(|&b| b.is_ascii_digit()) {
150 return Err(an_err!(DtErrKind::ExpectedValue, "2-digit second"));
151 }
152 fmt_buf[fmt_len..fmt_len + 2].copy_from_slice(b"%S");
153 fmt_len += 2;
154 pos += 2;
155 }
156
157 if pos < len_ {
159 if bytes[pos] == b'.' {
160 fmt_buf[fmt_len..fmt_len + 3].copy_from_slice(b"%.f");
161 fmt_len += 3;
162 pos += 1;
163 } else if bytes[pos].is_ascii_digit() {
164 fmt_buf[fmt_len..fmt_len + 2].copy_from_slice(b"%f");
165 fmt_len += 2;
166 }
167 while pos < len_ && bytes[pos].is_ascii_digit() {
168 pos += 1;
169 }
170 }
171
172 if pos + 1 < len_ && matches!(bytes[pos], b'Z' | b'z') {
174 fmt_buf[fmt_len] = bytes[pos];
175 fmt_len += 1;
176 pos += 1;
177 }
178 }
179
180 if pos < len_ {
181 if pos < len_ && !bytes[pos].is_ascii_alphabetic() {
183 fmt_buf[fmt_len] = bytes[pos];
184 fmt_len += 1;
185 pos += 1;
186 }
187 if pos < len_ {
188 let end = {
189 let mut i = pos;
190 while i < len_ && bytes[i].is_ascii_alphabetic() {
191 i += 1;
192 if i - pos > 8 {
193 break;
194 }
195 }
196 i
197 };
198 if Scale::from_abbrev(&input[pos..end]).is_some() {
199 fmt_buf[fmt_len..fmt_len + 2].copy_from_slice(b"%L");
200 fmt_len += 2;
201 pos += end - pos;
202 }
203 }
204 }
205
206 let format = match core::str::from_utf8(&fmt_buf[0..fmt_len]) {
207 Ok(f) => f,
208 Err(_) => {
209 return Err(an_err!(DtErrKind::InvalidBytes, "from utf8"));
210 }
211 };
212
213 TimeParts::from_str(format, &input[..pos], true, true, false)
214 }
215}