1use std::convert::TryFrom;
2use std::io::{Read, Write};
3use std::ops::Index;
4use std::slice::SliceIndex;
5
6use byteorder::{ReadBytesExt, WriteBytesExt};
7
8mod conversion;
9pub mod types;
10
11use self::types::FieldType;
12use crate::{Encoding, ErrorKind, FieldValue};
13pub use conversion::FieldConversionError;
14
15pub(crate) const DELETION_FLAG_SIZE: usize = 1; const FIELD_NAME_LENGTH: usize = 11;
17
18#[derive(Debug)]
19pub struct FieldName(String);
33
34impl TryFrom<&str> for FieldName {
35 type Error = &'static str;
36
37 fn try_from(name: &str) -> Result<Self, Self::Error> {
38 if name.len() > FIELD_NAME_LENGTH {
39 Err("FieldName byte representation cannot exceed 11 bytes")
40 } else {
41 Ok(Self(name.to_string()))
42 }
43 }
44}
45
46#[derive(Debug, PartialEq, Clone)]
48pub struct FieldInfo {
49 pub(crate) name: String,
51 pub(crate) field_type: FieldType,
53 pub(crate) displacement_field: [u8; 4],
54 pub(crate) field_length: u8,
55 pub(crate) num_decimal_places: u8,
56 pub(crate) flags: FieldFlags,
57 pub(crate) autoincrement_next_val: [u8; 5],
58 pub(crate) autoincrement_step: u8,
59}
60
61impl FieldInfo {
62 pub(crate) const SIZE: usize = 32;
63
64 pub fn name(&self) -> &str {
65 &self.name
66 }
67
68 pub fn field_type(&self) -> FieldType {
69 self.field_type
70 }
71
72 pub fn length(&self) -> u8 {
73 self.field_length
74 }
75
76 pub(crate) fn new(name: FieldName, field_type: FieldType, length: u8) -> Self {
77 Self {
78 name: name.0,
79 field_type,
80 displacement_field: [0u8; 4],
81 field_length: length,
82 num_decimal_places: 0,
83 flags: FieldFlags::default(),
84 autoincrement_next_val: [0u8; 5],
85 autoincrement_step: 0u8,
86 }
87 }
88
89 fn read_from<T: Read, E: Encoding>(source: &mut T, encoding: &E) -> Result<Self, ErrorKind> {
93 let mut name = [0u8; FIELD_NAME_LENGTH];
94 source.read_exact(&mut name)?;
95 let field_type = source.read_u8()?;
96
97 let mut displacement_field = [0u8; 4];
98 source.read_exact(&mut displacement_field)?;
99
100 let record_length = source.read_u8()?;
101 let num_decimal_places = source.read_u8()?;
102
103 let flags = FieldFlags(source.read_u8()?);
104
105 let mut autoincrement_next_val = [0u8; 5];
106
107 source.read_exact(&mut autoincrement_next_val)?;
108 let autoincrement_step = source.read_u8()?;
109
110 let mut _reserved = [0u8; 7];
111 source.read_exact(&mut _reserved)?;
112
113 let s = encoding
114 .decode(&name)?
115 .trim_matches(|c| c == '\u{0}')
116 .to_owned();
117
118 let field_type = FieldType::try_from(field_type as char)?;
119
120 Ok(Self {
121 name: s,
122 field_type,
123 displacement_field,
124 field_length: record_length,
125 num_decimal_places,
126 flags,
127 autoincrement_next_val,
128 autoincrement_step,
129 })
130 }
131
132 pub(crate) fn write_to<T: Write>(&self, dest: &mut T) -> std::io::Result<()> {
133 let num_bytes = self.name.len();
134 let mut name_bytes = [0u8; FIELD_NAME_LENGTH];
135 name_bytes[..num_bytes.min(FIELD_NAME_LENGTH)].copy_from_slice(self.name.as_bytes());
136 dest.write_all(&name_bytes)?;
137
138 dest.write_u8(u8::from(self.field_type))?;
139 dest.write_all(&self.displacement_field)?;
140 dest.write_u8(self.field_length)?;
141 dest.write_u8(self.num_decimal_places)?;
142 dest.write_u8(self.flags.0)?;
143 dest.write_all(&self.autoincrement_next_val)?;
144 dest.write_u8(self.autoincrement_step)?;
145
146 let reserved = [0u8; 7];
147 dest.write_all(&reserved)?;
148
149 Ok(())
150 }
151}
152
153#[derive(Debug)]
154pub struct FieldsInfo {
155 pub(crate) inner: Vec<FieldInfo>,
156}
157
158impl FieldsInfo {
159 pub(crate) fn read_from<R: Read, E: Encoding>(
160 source: &mut R,
161 num_fields: usize,
162 encoding: &E,
163 ) -> Result<Self, ErrorKind> {
164 let mut fields_info = Vec::<FieldInfo>::with_capacity(num_fields);
165 for _ in 0..num_fields {
166 let info = FieldInfo::read_from(source, encoding)?;
167 fields_info.push(info);
168 }
169
170 Ok(Self { inner: fields_info })
171 }
172
173 pub(crate) fn field_position_in_record(&self, index: usize) -> Option<usize> {
174 self.inner
175 .get(..index)
176 .map(|slc| slc.iter().map(|i| i.field_length as usize).sum::<usize>())
177 .map(|s| s + DELETION_FLAG_SIZE)
178 }
179
180 pub(crate) fn size_of_all_fields(&self) -> usize {
181 self.inner
182 .iter()
183 .map(|i| i.field_length as usize)
184 .sum::<usize>()
185 }
186
187 pub(crate) fn at_least_one_field_is_memo(&self) -> bool {
188 self.inner
189 .iter()
190 .any(|f_info| f_info.field_type == FieldType::Memo)
191 }
192
193 pub fn len(&self) -> usize {
194 self.inner.len()
195 }
196
197 pub fn iter(&self) -> std::slice::Iter<'_, FieldInfo> {
198 self.inner.iter()
199 }
200}
201
202impl AsRef<[FieldInfo]> for FieldsInfo {
203 fn as_ref(&self) -> &[FieldInfo] {
204 &self.inner
205 }
206}
207
208impl<I> Index<I> for FieldsInfo
209where
210 I: SliceIndex<[FieldInfo]>,
211{
212 type Output = I::Output;
213
214 fn index(&self, index: I) -> &Self::Output {
215 &self.inner.as_slice()[index]
216 }
217}
218
219impl std::fmt::Display for FieldInfo {
220 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
221 write!(
222 f,
223 "FieldInfo {{ Name: {}, Field Type: {} }}",
224 self.name, self.field_type
225 )
226 }
227}
228
229#[derive(Copy, Clone, Debug, PartialEq, Eq)]
230pub(crate) enum DeletionFlag {
231 NotDeleted,
232 Deleted,
233}
234
235impl DeletionFlag {
236 pub(crate) const fn to_byte(self) -> u8 {
237 match self {
238 Self::NotDeleted => 0x20,
239 Self::Deleted => 0x2A,
240 }
241 }
242
243 pub(crate) const fn from_byte(byte: u8) -> Self {
244 match byte {
245 0x20 => Self::NotDeleted,
246 0x2A => Self::Deleted,
247 _ => Self::NotDeleted,
249 }
250 }
251
252 pub(crate) fn read_from<T: Read>(source: &mut T) -> std::io::Result<Self> {
253 source.read_u8().map(Self::from_byte)
254 }
255
256 pub(crate) fn write_to<T: Write>(self, dst: &mut T) -> std::io::Result<()> {
257 dst.write_u8(self.to_byte())
258 }
259}
260#[derive(Debug, Copy, Clone, PartialEq, Default)]
262pub(crate) struct FieldFlags(u8);
263
264#[cfg(test)]
265mod test {
266 use super::*;
267 use std::io::Cursor;
268
269 #[test]
270 fn write_read_field_info() {
271 let field_info = FieldInfo::new(
272 FieldName::try_from("LICENSE").unwrap(),
273 FieldType::Character,
274 30,
275 );
276 let mut cursor = Cursor::new(Vec::<u8>::with_capacity(FieldInfo::SIZE));
277 field_info.write_to(&mut cursor).unwrap();
278
279 cursor.set_position(0);
280
281 let read_field_info = FieldInfo::read_from(&mut cursor, &crate::encoding::Ascii).unwrap();
282
283 assert_eq!(read_field_info, field_info);
284 }
285}