• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::fmt;
2 use std::io;
3 use std::iter::FromIterator;
4 use std::ops::{self, Range};
5 use std::result;
6 use std::str;
7 
8 use serde::de::Deserialize;
9 
10 use crate::byte_record::{ByteRecord, ByteRecordIter, Position};
11 use crate::deserializer::deserialize_string_record;
12 use crate::error::{Error, ErrorKind, FromUtf8Error, Result};
13 use crate::reader::Reader;
14 
15 /// A single CSV record stored as valid UTF-8 bytes.
16 ///
17 /// A string record permits reading or writing CSV rows that are valid UTF-8.
18 /// If string records are used to read CSV data that is not valid UTF-8, then
19 /// the CSV reader will return an invalid UTF-8 error. If you do need to read
20 /// possibly invalid UTF-8 data, then you should prefer using a
21 /// [`ByteRecord`](struct.ByteRecord.html),
22 /// since it makes no assumptions about UTF-8.
23 ///
24 /// If you are using the Serde (de)serialization APIs, then you probably never
25 /// need to interact with a `ByteRecord` or a `StringRecord`. However, there
26 /// are some circumstances in which you might need to use a raw record type
27 /// while still using Serde. For example, if you need to deserialize possibly
28 /// invalid UTF-8 fields, then you'll need to first read your record into a
29 /// `ByteRecord`, and then use `ByteRecord::deserialize` to run Serde. Another
30 /// reason for using the raw record deserialization APIs is if you're using
31 /// Serde to read into borrowed data such as a `&'a str` or a `&'a [u8]`.
32 ///
33 /// Two `StringRecord`s are compared on the basis of their field data. Any
34 /// position information associated with the records is ignored.
35 #[derive(Clone, Eq)]
36 pub struct StringRecord(ByteRecord);
37 
38 impl PartialEq for StringRecord {
eq(&self, other: &StringRecord) -> bool39     fn eq(&self, other: &StringRecord) -> bool {
40         self.0.iter_eq(&other.0)
41     }
42 }
43 
44 impl<T: AsRef<[u8]>> PartialEq<Vec<T>> for StringRecord {
eq(&self, other: &Vec<T>) -> bool45     fn eq(&self, other: &Vec<T>) -> bool {
46         self.0.iter_eq(other)
47     }
48 }
49 
50 impl<'a, T: AsRef<[u8]>> PartialEq<Vec<T>> for &'a StringRecord {
eq(&self, other: &Vec<T>) -> bool51     fn eq(&self, other: &Vec<T>) -> bool {
52         self.0.iter_eq(other)
53     }
54 }
55 
56 impl<T: AsRef<[u8]>> PartialEq<[T]> for StringRecord {
eq(&self, other: &[T]) -> bool57     fn eq(&self, other: &[T]) -> bool {
58         self.0.iter_eq(other)
59     }
60 }
61 
62 impl<'a, T: AsRef<[u8]>> PartialEq<[T]> for &'a StringRecord {
eq(&self, other: &[T]) -> bool63     fn eq(&self, other: &[T]) -> bool {
64         self.0.iter_eq(other)
65     }
66 }
67 
68 impl fmt::Debug for StringRecord {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result69     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
70         let fields: Vec<&str> = self.iter().collect();
71         write!(f, "StringRecord({:?})", fields)
72     }
73 }
74 
75 impl Default for StringRecord {
76     #[inline]
default() -> StringRecord77     fn default() -> StringRecord {
78         StringRecord::new()
79     }
80 }
81 
82 impl StringRecord {
83     /// Create a new empty `StringRecord`.
84     ///
85     /// Note that you may find the `StringRecord::from` constructor more
86     /// convenient, which is provided by an impl on the `From` trait.
87     ///
88     /// # Example: create an empty record
89     ///
90     /// ```
91     /// use csv::StringRecord;
92     ///
93     /// let record = StringRecord::new();
94     /// assert_eq!(record.len(), 0);
95     /// ```
96     ///
97     /// # Example: initialize a record from a `Vec`
98     ///
99     /// ```
100     /// use csv::StringRecord;
101     ///
102     /// let record = StringRecord::from(vec!["a", "b", "c"]);
103     /// assert_eq!(record.len(), 3);
104     /// ```
105     #[inline]
new() -> StringRecord106     pub fn new() -> StringRecord {
107         StringRecord(ByteRecord::new())
108     }
109 
110     /// Create a new empty `StringRecord` with the given capacity.
111     ///
112     /// `buffer` refers to the capacity of the buffer used to store the
113     /// actual row contents. `fields` refers to the number of fields one
114     /// might expect to store.
115     #[inline]
with_capacity(buffer: usize, fields: usize) -> StringRecord116     pub fn with_capacity(buffer: usize, fields: usize) -> StringRecord {
117         StringRecord(ByteRecord::with_capacity(buffer, fields))
118     }
119 
120     /// Create a new `StringRecord` from a `ByteRecord`.
121     ///
122     /// Note that this does UTF-8 validation. If the given `ByteRecord` does
123     /// not contain valid UTF-8, then this returns an error. The error includes
124     /// the UTF-8 error and the original `ByteRecord`.
125     ///
126     /// # Example: valid UTF-8
127     ///
128     /// ```
129     /// use std::error::Error;
130     /// use csv::{ByteRecord, StringRecord};
131     ///
132     /// # fn main() { example().unwrap(); }
133     /// fn example() -> Result<(), Box<dyn Error>> {
134     ///     let byte_record = ByteRecord::from(vec!["a", "b", "c"]);
135     ///     let str_record = StringRecord::from_byte_record(byte_record)?;
136     ///     assert_eq!(str_record.len(), 3);
137     ///     Ok(())
138     /// }
139     /// ```
140     ///
141     /// # Example: invalid UTF-8
142     ///
143     /// ```
144     /// use csv::{ByteRecord, StringRecord};
145     ///
146     /// let byte_record = ByteRecord::from(vec![
147     ///     &b"quux"[..], &b"foo\xFFbar"[..], &b"c"[..],
148     /// ]);
149     /// let err = StringRecord::from_byte_record(byte_record).unwrap_err();
150     /// assert_eq!(err.utf8_error().field(), 1);
151     /// assert_eq!(err.utf8_error().valid_up_to(), 3);
152     /// ```
153     #[inline]
from_byte_record( record: ByteRecord, ) -> result::Result<StringRecord, FromUtf8Error>154     pub fn from_byte_record(
155         record: ByteRecord,
156     ) -> result::Result<StringRecord, FromUtf8Error> {
157         match record.validate() {
158             Ok(()) => Ok(StringRecord(record)),
159             Err(err) => Err(FromUtf8Error::new(record, err)),
160         }
161     }
162 
163     /// Lossily create a new `StringRecord` from a `ByteRecord`.
164     ///
165     /// This is like `StringRecord::from_byte_record`, except all invalid UTF-8
166     /// sequences are replaced with the `U+FFFD REPLACEMENT CHARACTER`, which
167     /// looks like this: �.
168     ///
169     /// # Example: valid UTF-8
170     ///
171     /// ```
172     /// use csv::{ByteRecord, StringRecord};
173     ///
174     /// let byte_record = ByteRecord::from(vec!["a", "b", "c"]);
175     /// let str_record = StringRecord::from_byte_record_lossy(byte_record);
176     /// assert_eq!(str_record.len(), 3);
177     /// ```
178     ///
179     /// # Example: invalid UTF-8
180     ///
181     /// ```
182     /// use csv::{ByteRecord, StringRecord};
183     ///
184     /// let byte_record = ByteRecord::from(vec![
185     ///     &b"quux"[..], &b"foo\xFFbar"[..], &b"c"[..],
186     /// ]);
187     /// let str_record = StringRecord::from_byte_record_lossy(byte_record);
188     /// assert_eq!(&str_record[0], "quux");
189     /// assert_eq!(&str_record[1], "foo�bar");
190     /// assert_eq!(&str_record[2], "c");
191     /// ```
192     #[inline]
from_byte_record_lossy(record: ByteRecord) -> StringRecord193     pub fn from_byte_record_lossy(record: ByteRecord) -> StringRecord {
194         // If the record is valid UTF-8, then take the easy path.
195         if let Ok(()) = record.validate() {
196             return StringRecord(record);
197         }
198         // TODO: We can be faster here. Not sure if it's worth it.
199         let mut str_record =
200             StringRecord::with_capacity(record.as_slice().len(), record.len());
201         for field in &record {
202             str_record.push_field(&String::from_utf8_lossy(field));
203         }
204         str_record
205     }
206 
207     /// Deserialize this record.
208     ///
209     /// The `D` type parameter refers to the type that this record should be
210     /// deserialized into. The `'de` lifetime refers to the lifetime of the
211     /// `StringRecord`. The `'de` lifetime permits deserializing into structs
212     /// that borrow field data from this record.
213     ///
214     /// An optional `headers` parameter permits deserializing into a struct
215     /// based on its field names (corresponding to header values) rather than
216     /// the order in which the fields are defined.
217     ///
218     /// # Example: without headers
219     ///
220     /// This shows how to deserialize a single row into a struct based on the
221     /// order in which fields occur. This example also shows how to borrow
222     /// fields from the `StringRecord`, which results in zero allocation
223     /// deserialization.
224     ///
225     /// ```
226     /// use std::error::Error;
227     ///
228     /// use csv::StringRecord;
229     /// use serde::Deserialize;
230     ///
231     /// #[derive(Deserialize)]
232     /// struct Row<'a> {
233     ///     city: &'a str,
234     ///     country: &'a str,
235     ///     population: u64,
236     /// }
237     ///
238     /// # fn main() { example().unwrap() }
239     /// fn example() -> Result<(), Box<dyn Error>> {
240     ///     let record = StringRecord::from(vec![
241     ///         "Boston", "United States", "4628910",
242     ///     ]);
243     ///
244     ///     let row: Row = record.deserialize(None)?;
245     ///     assert_eq!(row.city, "Boston");
246     ///     assert_eq!(row.country, "United States");
247     ///     assert_eq!(row.population, 4628910);
248     ///     Ok(())
249     /// }
250     /// ```
251     ///
252     /// # Example: with headers
253     ///
254     /// This example is like the previous one, but shows how to deserialize
255     /// into a struct based on the struct's field names. For this to work,
256     /// you must provide a header row.
257     ///
258     /// This example also shows that you can deserialize into owned data
259     /// types (e.g., `String`) instead of borrowed data types (e.g., `&str`).
260     ///
261     /// ```
262     /// use std::error::Error;
263     ///
264     /// use csv::StringRecord;
265     /// use serde::Deserialize;
266     ///
267     /// #[derive(Deserialize)]
268     /// struct Row {
269     ///     city: String,
270     ///     country: String,
271     ///     population: u64,
272     /// }
273     ///
274     /// # fn main() { example().unwrap() }
275     /// fn example() -> Result<(), Box<dyn Error>> {
276     ///     // Notice that the fields are not in the same order
277     ///     // as the fields in the struct!
278     ///     let header = StringRecord::from(vec![
279     ///         "country", "city", "population",
280     ///     ]);
281     ///     let record = StringRecord::from(vec![
282     ///         "United States", "Boston", "4628910",
283     ///     ]);
284     ///
285     ///     let row: Row = record.deserialize(Some(&header))?;
286     ///     assert_eq!(row.city, "Boston");
287     ///     assert_eq!(row.country, "United States");
288     ///     assert_eq!(row.population, 4628910);
289     ///     Ok(())
290     /// }
291     /// ```
deserialize<'de, D: Deserialize<'de>>( &'de self, headers: Option<&'de StringRecord>, ) -> Result<D>292     pub fn deserialize<'de, D: Deserialize<'de>>(
293         &'de self,
294         headers: Option<&'de StringRecord>,
295     ) -> Result<D> {
296         deserialize_string_record(self, headers)
297     }
298 
299     /// Returns an iterator over all fields in this record.
300     ///
301     /// # Example
302     ///
303     /// This example shows how to iterate over each field in a `StringRecord`.
304     ///
305     /// ```
306     /// use csv::StringRecord;
307     ///
308     /// let record = StringRecord::from(vec!["a", "b", "c"]);
309     /// for field in record.iter() {
310     ///     assert!(field == "a" || field == "b" || field == "c");
311     /// }
312     /// ```
313     #[inline]
iter(&self) -> StringRecordIter314     pub fn iter(&self) -> StringRecordIter {
315         self.into_iter()
316     }
317 
318     /// Return the field at index `i`.
319     ///
320     /// If no field at index `i` exists, then this returns `None`.
321     ///
322     /// # Example
323     ///
324     /// ```
325     /// use csv::StringRecord;
326     ///
327     /// let record = StringRecord::from(vec!["a", "b", "c"]);
328     /// assert_eq!(record.get(1), Some("b"));
329     /// assert_eq!(record.get(3), None);
330     /// ```
331     #[inline]
get(&self, i: usize) -> Option<&str>332     pub fn get(&self, i: usize) -> Option<&str> {
333         self.0.get(i).map(|bytes| {
334             debug_assert!(str::from_utf8(bytes).is_ok());
335             // This is safe because we guarantee that all string records
336             // have a valid UTF-8 buffer. It's also safe because we
337             // individually check each field for valid UTF-8.
338             unsafe { str::from_utf8_unchecked(bytes) }
339         })
340     }
341 
342     /// Returns true if and only if this record is empty.
343     ///
344     /// # Example
345     ///
346     /// ```
347     /// use csv::StringRecord;
348     ///
349     /// assert!(StringRecord::new().is_empty());
350     /// ```
351     #[inline]
is_empty(&self) -> bool352     pub fn is_empty(&self) -> bool {
353         self.len() == 0
354     }
355 
356     /// Returns the number of fields in this record.
357     ///
358     /// # Example
359     ///
360     /// ```
361     /// use csv::StringRecord;
362     ///
363     /// let record = StringRecord::from(vec!["a", "b", "c"]);
364     /// assert_eq!(record.len(), 3);
365     /// ```
366     #[inline]
len(&self) -> usize367     pub fn len(&self) -> usize {
368         self.0.len()
369     }
370 
371     /// Truncate this record to `n` fields.
372     ///
373     /// If `n` is greater than the number of fields in this record, then this
374     /// has no effect.
375     ///
376     /// # Example
377     ///
378     /// ```
379     /// use csv::StringRecord;
380     ///
381     /// let mut record = StringRecord::from(vec!["a", "b", "c"]);
382     /// assert_eq!(record.len(), 3);
383     /// record.truncate(1);
384     /// assert_eq!(record.len(), 1);
385     /// assert_eq!(record, vec!["a"]);
386     /// ```
387     #[inline]
truncate(&mut self, n: usize)388     pub fn truncate(&mut self, n: usize) {
389         self.0.truncate(n);
390     }
391 
392     /// Clear this record so that it has zero fields.
393     ///
394     /// Note that it is not necessary to clear the record to reuse it with
395     /// the CSV reader.
396     ///
397     /// # Example
398     ///
399     /// ```
400     /// use csv::StringRecord;
401     ///
402     /// let mut record = StringRecord::from(vec!["a", "b", "c"]);
403     /// assert_eq!(record.len(), 3);
404     /// record.clear();
405     /// assert_eq!(record.len(), 0);
406     /// ```
407     #[inline]
clear(&mut self)408     pub fn clear(&mut self) {
409         self.0.clear();
410     }
411 
412     /// Trim the fields of this record so that leading and trailing whitespace
413     /// is removed.
414     ///
415     /// This method uses the Unicode definition of whitespace.
416     ///
417     /// # Example
418     ///
419     /// ```
420     /// use csv::StringRecord;
421     ///
422     /// let mut record = StringRecord::from(vec![
423     ///     "  ", "\u{3000}\tfoo ", "bar  ", "b a z",
424     /// ]);
425     /// record.trim();
426     /// assert_eq!(record, vec!["", "foo", "bar", "b a z"]);
427     /// ```
trim(&mut self)428     pub fn trim(&mut self) {
429         let length = self.len();
430         if length == 0 {
431             return;
432         }
433         // TODO: We could likely do this in place, but for now, we allocate.
434         let mut trimmed =
435             StringRecord::with_capacity(self.as_slice().len(), self.len());
436         trimmed.set_position(self.position().cloned());
437         for field in &*self {
438             trimmed.push_field(field.trim());
439         }
440         *self = trimmed;
441     }
442 
443     /// Add a new field to this record.
444     ///
445     /// # Example
446     ///
447     /// ```
448     /// use csv::StringRecord;
449     ///
450     /// let mut record = StringRecord::new();
451     /// record.push_field("foo");
452     /// assert_eq!(&record[0], "foo");
453     /// ```
454     #[inline]
push_field(&mut self, field: &str)455     pub fn push_field(&mut self, field: &str) {
456         self.0.push_field(field.as_bytes());
457     }
458 
459     /// Return the position of this record, if available.
460     ///
461     /// # Example
462     ///
463     /// ```
464     /// use std::error::Error;
465     /// use csv::{StringRecord, ReaderBuilder};
466     ///
467     /// # fn main() { example().unwrap(); }
468     /// fn example() -> Result<(), Box<dyn Error>> {
469     ///     let mut record = StringRecord::new();
470     ///     let mut rdr = ReaderBuilder::new()
471     ///         .has_headers(false)
472     ///         .from_reader("a,b,c\nx,y,z".as_bytes());
473     ///
474     ///     assert!(rdr.read_record(&mut record)?);
475     ///     {
476     ///         let pos = record.position().expect("a record position");
477     ///         assert_eq!(pos.byte(), 0);
478     ///         assert_eq!(pos.line(), 1);
479     ///         assert_eq!(pos.record(), 0);
480     ///     }
481     ///
482     ///     assert!(rdr.read_record(&mut record)?);
483     ///     {
484     ///         let pos = record.position().expect("a record position");
485     ///         assert_eq!(pos.byte(), 6);
486     ///         assert_eq!(pos.line(), 2);
487     ///         assert_eq!(pos.record(), 1);
488     ///     }
489     ///
490     ///     // Finish the CSV reader for good measure.
491     ///     assert!(!rdr.read_record(&mut record)?);
492     ///     Ok(())
493     /// }
494     /// ```
495     #[inline]
position(&self) -> Option<&Position>496     pub fn position(&self) -> Option<&Position> {
497         self.0.position()
498     }
499 
500     /// Set the position of this record.
501     ///
502     /// # Example
503     ///
504     /// ```
505     /// use csv::{StringRecord, Position};
506     ///
507     /// let mut record = StringRecord::from(vec!["a", "b", "c"]);
508     /// let mut pos = Position::new();
509     /// pos.set_byte(100);
510     /// pos.set_line(4);
511     /// pos.set_record(2);
512     ///
513     /// record.set_position(Some(pos.clone()));
514     /// assert_eq!(record.position(), Some(&pos));
515     /// ```
516     #[inline]
set_position(&mut self, pos: Option<Position>)517     pub fn set_position(&mut self, pos: Option<Position>) {
518         self.0.set_position(pos);
519     }
520 
521     /// Return the start and end position of a field in this record.
522     ///
523     /// If no such field exists at the given index, then return `None`.
524     ///
525     /// The range returned can be used with the slice returned by `as_slice`.
526     /// Namely, the range returned is guaranteed to start and end at valid
527     /// UTF-8 sequence boundaries.
528     ///
529     /// # Example
530     ///
531     /// ```
532     /// use csv::StringRecord;
533     ///
534     /// let record = StringRecord::from(vec!["foo", "quux", "z"]);
535     /// let range = record.range(1).expect("a record range");
536     /// assert_eq!(&record.as_slice()[range], "quux");
537     /// ```
538     #[inline]
range(&self, i: usize) -> Option<Range<usize>>539     pub fn range(&self, i: usize) -> Option<Range<usize>> {
540         self.0.range(i)
541     }
542 
543     /// Return the entire row as a single string slice. The slice returned
544     /// stores all fields contiguously. The boundaries of each field can be
545     /// determined via the `range` method.
546     ///
547     /// # Example
548     ///
549     /// ```
550     /// use csv::StringRecord;
551     ///
552     /// let record = StringRecord::from(vec!["foo", "quux", "z"]);
553     /// assert_eq!(record.as_slice(), "fooquuxz");
554     /// ```
555     #[inline]
as_slice(&self) -> &str556     pub fn as_slice(&self) -> &str {
557         debug_assert!(str::from_utf8(self.0.as_slice()).is_ok());
558         // This is safe because we guarantee that each field is valid UTF-8.
559         // If each field is valid UTF-8, then the entire buffer (up to the end
560         // of the last field) must also be valid UTF-8.
561         unsafe { str::from_utf8_unchecked(self.0.as_slice()) }
562     }
563 
564     /// Return a reference to this record's raw
565     /// [`ByteRecord`](struct.ByteRecord.html).
566     ///
567     /// # Example
568     ///
569     /// ```
570     /// use csv::StringRecord;
571     ///
572     /// let str_record = StringRecord::from(vec!["a", "b", "c"]);
573     /// let byte_record = str_record.as_byte_record();
574     /// assert_eq!(&byte_record[2], b"c");
575     /// ```
576     #[inline]
as_byte_record(&self) -> &ByteRecord577     pub fn as_byte_record(&self) -> &ByteRecord {
578         &self.0
579     }
580 
581     /// Convert this `StringRecord` into a
582     /// [`ByteRecord`](struct.ByteRecord.html).
583     ///
584     /// # Example
585     ///
586     /// ```
587     /// use csv::StringRecord;
588     ///
589     /// let str_record = StringRecord::from(vec!["a", "b", "c"]);
590     /// let byte_record = str_record.into_byte_record();
591     /// assert_eq!(&byte_record[2], b"c");
592     /// ```
593     ///
594     /// Note that this can also be achieved using the `From` impl:
595     ///
596     /// ```
597     /// use csv::{ByteRecord, StringRecord};
598     ///
599     /// // Using ByteRecord::from...
600     /// let str_record = StringRecord::from(vec!["a", "b", "c"]);
601     /// assert_eq!(ByteRecord::from(str_record).len(), 3);
602     ///
603     /// // Using StringRecord::into...
604     /// let str_record = StringRecord::from(vec!["a", "b", "c"]);
605     /// let byte_record: ByteRecord = str_record.into();
606     /// assert_eq!(byte_record.len(), 3);
607     /// ```
608     #[inline]
into_byte_record(self) -> ByteRecord609     pub fn into_byte_record(self) -> ByteRecord {
610         self.0
611     }
612 
613     /// Clone this record, but only copy `fields` up to the end of bounds. This
614     /// is useful when one wants to copy a record, but not necessarily any
615     /// excess capacity in that record.
616     #[inline]
clone_truncated(&self) -> StringRecord617     pub(crate) fn clone_truncated(&self) -> StringRecord {
618         StringRecord(self.0.clone_truncated())
619     }
620 
621     /// A safe function for reading CSV data into a `StringRecord`.
622     ///
623     /// This relies on the internal representation of `StringRecord`.
624     #[inline(always)]
read<R: io::Read>( &mut self, rdr: &mut Reader<R>, ) -> Result<bool>625     pub(crate) fn read<R: io::Read>(
626         &mut self,
627         rdr: &mut Reader<R>,
628     ) -> Result<bool> {
629         // SAFETY: This code is critical to upholding the safety of other code
630         // blocks in this module. Namely, after calling `read_byte_record`,
631         // it is possible for `record` to contain invalid UTF-8. We check for
632         // this in the `validate` method, and if it does have invalid UTF-8, we
633         // clear the record. (It is bad for `record` to contain invalid UTF-8
634         // because other accessor methods, like `get`, assume that every field
635         // is valid UTF-8.)
636         let pos = rdr.position().clone();
637         let read_res = rdr.read_byte_record(&mut self.0);
638         let utf8_res = match self.0.validate() {
639             Ok(()) => Ok(()),
640             Err(err) => {
641                 // If this record isn't valid UTF-8, then completely wipe it.
642                 self.0.clear();
643                 Err(err)
644             }
645         };
646         match (read_res, utf8_res) {
647             (Err(err), _) => Err(err),
648             (Ok(_), Err(err)) => {
649                 Err(Error::new(ErrorKind::Utf8 { pos: Some(pos), err: err }))
650             }
651             (Ok(eof), Ok(())) => Ok(eof),
652         }
653     }
654 }
655 
656 impl ops::Index<usize> for StringRecord {
657     type Output = str;
658     #[inline]
index(&self, i: usize) -> &str659     fn index(&self, i: usize) -> &str {
660         self.get(i).unwrap()
661     }
662 }
663 
664 impl<T: AsRef<str>> From<Vec<T>> for StringRecord {
665     #[inline]
from(xs: Vec<T>) -> StringRecord666     fn from(xs: Vec<T>) -> StringRecord {
667         StringRecord::from_iter(xs.into_iter())
668     }
669 }
670 
671 impl<'a, T: AsRef<str>> From<&'a [T]> for StringRecord {
672     #[inline]
from(xs: &'a [T]) -> StringRecord673     fn from(xs: &'a [T]) -> StringRecord {
674         StringRecord::from_iter(xs)
675     }
676 }
677 
678 impl<T: AsRef<str>> FromIterator<T> for StringRecord {
679     #[inline]
from_iter<I: IntoIterator<Item = T>>(iter: I) -> StringRecord680     fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> StringRecord {
681         let mut record = StringRecord::new();
682         record.extend(iter);
683         record
684     }
685 }
686 
687 impl<T: AsRef<str>> Extend<T> for StringRecord {
688     #[inline]
extend<I: IntoIterator<Item = T>>(&mut self, iter: I)689     fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
690         for x in iter {
691             self.push_field(x.as_ref());
692         }
693     }
694 }
695 
696 impl<'a> IntoIterator for &'a StringRecord {
697     type IntoIter = StringRecordIter<'a>;
698     type Item = &'a str;
699 
700     #[inline]
into_iter(self) -> StringRecordIter<'a>701     fn into_iter(self) -> StringRecordIter<'a> {
702         StringRecordIter(self.0.iter())
703     }
704 }
705 
706 /// An iterator over the fields in a string record.
707 ///
708 /// The `'r` lifetime variable refers to the lifetime of the `StringRecord`
709 /// that is being iterated over.
710 #[derive(Clone)]
711 pub struct StringRecordIter<'r>(ByteRecordIter<'r>);
712 
713 impl<'r> Iterator for StringRecordIter<'r> {
714     type Item = &'r str;
715 
716     #[inline]
next(&mut self) -> Option<&'r str>717     fn next(&mut self) -> Option<&'r str> {
718         self.0.next().map(|bytes| {
719             debug_assert!(str::from_utf8(bytes).is_ok());
720             // See StringRecord::get for safety argument.
721             unsafe { str::from_utf8_unchecked(bytes) }
722         })
723     }
724 
725     #[inline]
size_hint(&self) -> (usize, Option<usize>)726     fn size_hint(&self) -> (usize, Option<usize>) {
727         self.0.size_hint()
728     }
729 
730     #[inline]
count(self) -> usize731     fn count(self) -> usize {
732         self.0.len()
733     }
734 }
735 
736 impl<'r> DoubleEndedIterator for StringRecordIter<'r> {
737     #[inline]
next_back(&mut self) -> Option<&'r str>738     fn next_back(&mut self) -> Option<&'r str> {
739         self.0.next_back().map(|bytes| {
740             debug_assert!(str::from_utf8(bytes).is_ok());
741             // See StringRecord::get for safety argument.
742             unsafe { str::from_utf8_unchecked(bytes) }
743         })
744     }
745 }
746 
747 #[cfg(test)]
748 mod tests {
749     use crate::string_record::StringRecord;
750 
751     #[test]
trim_front()752     fn trim_front() {
753         let mut rec = StringRecord::from(vec![" abc"]);
754         rec.trim();
755         assert_eq!(rec.get(0), Some("abc"));
756 
757         let mut rec = StringRecord::from(vec![" abc", "  xyz"]);
758         rec.trim();
759         assert_eq!(rec.get(0), Some("abc"));
760         assert_eq!(rec.get(1), Some("xyz"));
761     }
762 
763     #[test]
trim_back()764     fn trim_back() {
765         let mut rec = StringRecord::from(vec!["abc "]);
766         rec.trim();
767         assert_eq!(rec.get(0), Some("abc"));
768 
769         let mut rec = StringRecord::from(vec!["abc ", "xyz  "]);
770         rec.trim();
771         assert_eq!(rec.get(0), Some("abc"));
772         assert_eq!(rec.get(1), Some("xyz"));
773     }
774 
775     #[test]
trim_both()776     fn trim_both() {
777         let mut rec = StringRecord::from(vec![" abc "]);
778         rec.trim();
779         assert_eq!(rec.get(0), Some("abc"));
780 
781         let mut rec = StringRecord::from(vec![" abc ", "  xyz  "]);
782         rec.trim();
783         assert_eq!(rec.get(0), Some("abc"));
784         assert_eq!(rec.get(1), Some("xyz"));
785     }
786 
787     #[test]
trim_does_not_panic_on_empty_records_1()788     fn trim_does_not_panic_on_empty_records_1() {
789         let mut rec = StringRecord::from(vec![""]);
790         rec.trim();
791         assert_eq!(rec.get(0), Some(""));
792     }
793 
794     #[test]
trim_does_not_panic_on_empty_records_2()795     fn trim_does_not_panic_on_empty_records_2() {
796         let mut rec = StringRecord::from(vec!["", ""]);
797         rec.trim();
798         assert_eq!(rec.get(0), Some(""));
799         assert_eq!(rec.get(1), Some(""));
800     }
801 
802     #[test]
trim_does_not_panic_on_empty_records_3()803     fn trim_does_not_panic_on_empty_records_3() {
804         let mut rec = StringRecord::new();
805         rec.trim();
806         assert_eq!(rec.as_slice().len(), 0);
807     }
808 
809     #[test]
trim_whitespace_only()810     fn trim_whitespace_only() {
811         let mut rec = StringRecord::from(vec![
812             "\u{0009}\u{000A}\u{000B}\u{000C}\u{000D}\u{0020}\u{0085}\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{2028}\u{2029}\u{202F}\u{205F}\u{3000}",
813         ]);
814         rec.trim();
815         assert_eq!(rec.get(0), Some(""));
816     }
817 
818     // Check that record equality respects field boundaries.
819     //
820     // Regression test for #138.
821     #[test]
eq_field_boundaries()822     fn eq_field_boundaries() {
823         let test1 = StringRecord::from(vec!["12", "34"]);
824         let test2 = StringRecord::from(vec!["123", "4"]);
825 
826         assert_ne!(test1, test2);
827     }
828 
829     // Check that record equality respects number of fields.
830     //
831     // Regression test for #138.
832     #[test]
eq_record_len()833     fn eq_record_len() {
834         let test1 = StringRecord::from(vec!["12", "34", "56"]);
835         let test2 = StringRecord::from(vec!["12", "34"]);
836         assert_ne!(test1, test2);
837     }
838 }
839