dbase/field/
mod.rs

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; // 1 byte
16const FIELD_NAME_LENGTH: usize = 11;
17
18#[derive(Debug)]
19/// Wrapping struct to create a FieldName from a String.
20///
21/// FieldNames in the dBase format cannot exceed 11 bytes (not char).
22///
23/// # Examples
24///
25/// ```
26/// use dbase::FieldName;
27/// use std::convert::TryFrom;
28///
29/// let name = FieldName::try_from("Small Name");
30/// assert!(name.is_ok())
31/// ```
32pub 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/// Struct giving the info for a record field
47#[derive(Debug, PartialEq, Clone)]
48pub struct FieldInfo {
49    /// The name of the field
50    pub(crate) name: String,
51    /// The field type
52    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    /// Reads with the given encoding.
90    ///
91    /// The encoding is used only for the name
92    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            // Silently consider other values as not deleted
248            _ => 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/// Flags describing a field
261#[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}