documentrecord
authorBen Pfaff <blp@cs.stanford.edu>
Fri, 22 Dec 2023 20:23:53 +0000 (12:23 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Fri, 22 Dec 2023 20:23:53 +0000 (12:23 -0800)
rust/src/cooked.rs
rust/src/raw.rs

index b3c0ff74bf585aaed00f0974a8560d1806c039d1..095bfe507db1bc1297168fa7e4a8bfdefaa072f8 100644 (file)
@@ -8,7 +8,7 @@ use crate::{
     endian::Endian,
     format::{Error as FormatError, Spec, UncheckedSpec},
     identifier::{Error as IdError, Identifier},
-    raw::{self, RawStr, RawString, VarType},
+    raw::{self, RawStr, RawString, VarType, RawDocumentLine},
 };
 use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
 use encoding_rs::{DecoderResult, Encoding};
@@ -215,7 +215,7 @@ struct Headers<'a> {
     header: Option<&'a raw::HeaderRecord<RawString>>,
     variables: Vec<&'a raw::VariableRecord<RawString, RawStr<8>>>,
     value_labels: Vec<&'a raw::ValueLabelRecord<RawStr<8>, RawString>>,
-    document: Option<&'a raw::DocumentRecord>,
+    document: Option<&'a raw::DocumentRecord<RawDocumentLine>>,
     integer_info: Option<&'a raw::IntegerInfoRecord>,
     float_info: Option<&'a raw::FloatInfoRecord>,
     variable_sets: Vec<&'a raw::TextRecord>,
@@ -780,7 +780,7 @@ impl TryDecode for VariableRecord {
 pub struct DocumentRecord(Vec<String>);
 
 impl TryDecode for DocumentRecord {
-    type Input = crate::raw::DocumentRecord;
+    type Input = crate::raw::DocumentRecord<RawDocumentLine>;
 
     fn try_decode(
         decoder: &mut Decoder,
index af29cdf61e5dd1b26a64587350e3037c58f3b4dd..e0c5a79efff97e3c8f228d7677f791077260673e 100644 (file)
@@ -161,7 +161,7 @@ pub enum Record {
     Header(HeaderRecord<RawString>),
     Variable(VariableRecord<RawString, RawStr<8>>),
     ValueLabel(ValueLabelRecord<RawStr<8>, RawString>),
-    Document(DocumentRecord),
+    Document(DocumentRecord<RawDocumentLine>),
     IntegerInfo(IntegerInfoRecord),
     FloatInfo(FloatInfoRecord),
     VariableSets(TextRecord),
@@ -393,8 +393,8 @@ struct Decoder {
 }
 
 impl Decoder {
-    fn decode<'a>(&self, input: &'a RawString) -> Cow<'a, str> {
-        let (output, malformed) = self.encoding.decode_without_bom_handling(&input.0);
+    fn decode_slice<'a>(&self, input: &'a [u8]) -> Cow<'a, str> {
+        let (output, malformed) = self.encoding.decode_without_bom_handling(input);
         if malformed {
             (self.warn)(Error::MalformedString {
                 encoding: self.encoding.name().into(),
@@ -403,6 +403,10 @@ impl Decoder {
         }
         output
     }
+        
+    fn decode<'a>(&self, input: &'a RawString) -> Cow<'a, str> {
+        self.decode_slice(input.0.as_slice())
+    }
 
     /// Returns `input` decoded from `self.encoding` into UTF-8 such that
     /// re-encoding the result back into `self.encoding` will have exactly the
@@ -1413,23 +1417,26 @@ impl ValueLabelRecord<RawStr<8>, RawString> {
 }
 
 #[derive(Clone, Debug)]
-pub struct DocumentRecord {
+pub struct DocumentRecord<S>
+where
+    S: Debug,
+{
     pub offsets: Range<u64>,
 
     /// The document, as an array of 80-byte lines.
-    pub lines: Vec<DocumentLine>,
+    pub lines: Vec<S>,
 }
 
-pub type DocumentLine = RawStr<{ DocumentRecord::LINE_LEN }>;
+pub type RawDocumentLine = RawStr<DOC_LINE_LEN>;
 
-impl DocumentRecord {
-    /// Length of a line in a document.  Document lines are fixed-length and
-    /// padded on the right with spaces.
-    pub const LINE_LEN: usize = 80;
+/// Length of a line in a document.  Document lines are fixed-length and
+/// padded on the right with spaces.
+pub const DOC_LINE_LEN: usize = 80;
 
+impl DocumentRecord<RawDocumentLine> {
     /// Maximum number of lines we will accept in a document.  This is simply
     /// the maximum number that will fit in a 32-bit space.
-    pub const MAX_LINES: usize = i32::MAX as usize / Self::LINE_LEN;
+    pub const MAX_LINES: usize = i32::MAX as usize / DOC_LINE_LEN;
 
     fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<Record, Error> {
         let start_offset = r.stream_position()?;
@@ -1444,7 +1451,7 @@ impl DocumentRecord {
         } else {
             let mut lines = Vec::with_capacity(n);
             for _ in 0..n {
-                lines.push(RawStr::<{ DocumentRecord::LINE_LEN }>(read_bytes(r)?));
+                lines.push(RawStr(read_bytes(r)?));
             }
             let end_offset = r.stream_position()?;
             Ok(Record::Document(DocumentRecord {
@@ -1453,9 +1460,19 @@ impl DocumentRecord {
             }))
         }
     }
+
+    fn decode<'a>(&'a self, decoder: &Decoder) -> DocumentRecord<Cow<'a, str>> {
+        DocumentRecord {
+            offsets: self.offsets.clone(),
+            lines: self.lines.iter().map(|s| decoder.decode_slice(&s.0)).collect(),
+        }
+    }
 }
 
-impl Header for DocumentRecord {
+impl<S> Header for DocumentRecord<S>
+where
+    S: Debug,
+{
     fn offsets(&self) -> Range<u64> {
         self.offsets.clone()
     }