Skip to content

Commit

Permalink
idioms: use pub(crate), use Error::source
Browse files Browse the repository at this point in the history
  • Loading branch information
BurntSushi committed Jun 26, 2019
1 parent 9423d80 commit 0c7005f
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 200 deletions.
149 changes: 71 additions & 78 deletions src/byte_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,79 +12,6 @@ use crate::deserializer::deserialize_byte_record;
use crate::error::{new_utf8_error, Result, Utf8Error};
use crate::string_record::StringRecord;

/// Retrieve the underlying parts of a byte record.
#[inline]
pub fn as_parts(record: &mut ByteRecord) -> (&mut Vec<u8>, &mut Vec<usize>) {
// TODO(burntsushi): Use `pub(crate)` when it stabilizes.
// (&mut record.fields, &mut record.bounds.ends)
let inner = &mut *record.0;
(&mut inner.fields, &mut inner.bounds.ends)
}

/// Set the number of fields in the given record record.
#[inline]
pub fn set_len(record: &mut ByteRecord, len: usize) {
// TODO(burntsushi): Use `pub(crate)` when it stabilizes.
record.0.bounds.len = len;
}

/// Expand the capacity for storing fields.
#[inline]
pub fn expand_fields(record: &mut ByteRecord) {
// TODO(burntsushi): Use `pub(crate)` when it stabilizes.
let new_len = record.0.fields.len().checked_mul(2).unwrap();
record.0.fields.resize(cmp::max(4, new_len), 0);
}

/// Expand the capacity for storing field ending positions.
#[inline]
pub fn expand_ends(record: &mut ByteRecord) {
// TODO(burntsushi): Use `pub(crate)` when it stabilizes.
record.0.bounds.expand();
}

/// Validate the given record as UTF-8.
///
/// If it's not UTF-8, return an error.
#[inline]
pub fn validate(record: &ByteRecord) -> result::Result<(), Utf8Error> {
// TODO(burntsushi): Use `pub(crate)` when it stabilizes.

// If the entire buffer is ASCII, then we have nothing to fear.
if record.0.fields[..record.0.bounds.end()].iter().all(|&b| b <= 0x7F) {
return Ok(());
}
// Otherwise, we must check each field individually to ensure that
// it's valid UTF-8.
for (i, field) in record.iter().enumerate() {
if let Err(err) = str::from_utf8(field) {
return Err(new_utf8_error(i, err.valid_up_to()));
}
}
Ok(())
}

/// Compare the given byte record with the iterator of fields for equality.
pub fn eq<I, T>(record: &ByteRecord, other: I) -> bool
where
I: IntoIterator<Item = T>,
T: AsRef<[u8]>,
{
let mut it_record = record.iter();
let mut it_other = other.into_iter();
loop {
match (it_record.next(), it_other.next()) {
(None, None) => return true,
(None, Some(_)) | (Some(_), None) => return false,
(Some(x), Some(y)) => {
if x != y.as_ref() {
return false;
}
}
}
}
}

/// A single CSV record stored as raw bytes.
///
/// A byte record permits reading or writing CSV rows that are not UTF-8.
Expand Down Expand Up @@ -118,25 +45,25 @@ impl PartialEq for ByteRecord {

impl<T: AsRef<[u8]>> PartialEq<Vec<T>> for ByteRecord {
fn eq(&self, other: &Vec<T>) -> bool {
eq(self, other)
self.iter_eq(other)
}
}

impl<'a, T: AsRef<[u8]>> PartialEq<Vec<T>> for &'a ByteRecord {
fn eq(&self, other: &Vec<T>) -> bool {
eq(self, other)
self.iter_eq(other)
}
}

impl<T: AsRef<[u8]>> PartialEq<[T]> for ByteRecord {
fn eq(&self, other: &[T]) -> bool {
eq(self, other)
self.iter_eq(other)
}
}

impl<'a, T: AsRef<[u8]>> PartialEq<[T]> for &'a ByteRecord {
fn eq(&self, other: &[T]) -> bool {
eq(self, other)
self.iter_eq(other)
}
}

Expand Down Expand Up @@ -488,7 +415,7 @@ impl ByteRecord {
pub fn push_field(&mut self, field: &[u8]) {
let (s, e) = (self.0.bounds.end(), self.0.bounds.end() + field.len());
while e > self.0.fields.len() {
expand_fields(self);
self.expand_fields();
}
self.0.fields[s..e].copy_from_slice(field);
self.0.bounds.add(e);
Expand Down Expand Up @@ -593,6 +520,72 @@ impl ByteRecord {
pub fn as_slice(&self) -> &[u8] {
&self.0.fields[..self.0.bounds.end()]
}

/// Retrieve the underlying parts of a byte record.
#[inline]
pub(crate) fn as_parts(&mut self) -> (&mut Vec<u8>, &mut Vec<usize>) {
let inner = &mut *self.0;
(&mut inner.fields, &mut inner.bounds.ends)
}

/// Set the number of fields in the given record record.
#[inline]
pub(crate) fn set_len(&mut self, len: usize) {
self.0.bounds.len = len;
}

/// Expand the capacity for storing fields.
#[inline]
pub(crate) fn expand_fields(&mut self) {
let new_len = self.0.fields.len().checked_mul(2).unwrap();
self.0.fields.resize(cmp::max(4, new_len), 0);
}

/// Expand the capacity for storing field ending positions.
#[inline]
pub(crate) fn expand_ends(&mut self) {
self.0.bounds.expand();
}

/// Validate the given record as UTF-8.
///
/// If it's not UTF-8, return an error.
#[inline]
pub(crate) fn validate(&self) -> result::Result<(), Utf8Error> {
// If the entire buffer is ASCII, then we have nothing to fear.
if self.0.fields[..self.0.bounds.end()].iter().all(|&b| b <= 0x7F) {
return Ok(());
}
// Otherwise, we must check each field individually to ensure that
// it's valid UTF-8.
for (i, field) in self.iter().enumerate() {
if let Err(err) = str::from_utf8(field) {
return Err(new_utf8_error(i, err.valid_up_to()));
}
}
Ok(())
}

/// Compare the given byte record with the iterator of fields for equality.
pub(crate) fn iter_eq<I, T>(&self, other: I) -> bool
where
I: IntoIterator<Item = T>,
T: AsRef<[u8]>,
{
let mut it_record = self.iter();
let mut it_other = other.into_iter();
loop {
match (it_record.next(), it_other.next()) {
(None, None) => return true,
(None, Some(_)) | (Some(_), None) => return false,
(Some(x), Some(y)) => {
if x != y.as_ref() {
return false;
}
}
}
}
}
}

/// A position in CSV data.
Expand Down
6 changes: 3 additions & 3 deletions src/deserializer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use serde::de::{
};

use crate::byte_record::{ByteRecord, ByteRecordIter};
use crate::error::{new_error, Error, ErrorKind};
use crate::error::{Error, ErrorKind};
use crate::string_record::{StringRecord, StringRecordIter};

use self::DeserializeErrorKind as DEK;
Expand All @@ -27,7 +27,7 @@ pub fn deserialize_string_record<'de, D: Deserialize<'de>>(
field: 0,
});
D::deserialize(&mut deser).map_err(|err| {
new_error(ErrorKind::Deserialize {
Error::new(ErrorKind::Deserialize {
pos: record.position().map(Clone::clone),
err: err,
})
Expand All @@ -44,7 +44,7 @@ pub fn deserialize_byte_record<'de, D: Deserialize<'de>>(
field: 0,
});
D::deserialize(&mut deser).map_err(|err| {
new_error(ErrorKind::Deserialize {
Error::new(ErrorKind::Deserialize {
pos: record.position().map(Clone::clone),
err: err,
})
Expand Down
78 changes: 25 additions & 53 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,10 @@ use std::error::Error as StdError;
use std::fmt;
use std::io;
use std::result;
use std::str;

use crate::byte_record::{ByteRecord, Position};
use crate::deserializer::DeserializeError;

/// A crate private constructor for `Error`.
pub fn new_error(kind: ErrorKind) -> Error {
// TODO(burntsushi): Use `pub(crate)` when it stabilizes.
Error(Box::new(kind))
}

/// A type alias for `Result<T, csv::Error>`.
pub type Result<T> = result::Result<T, Error>;

Expand All @@ -28,6 +21,11 @@ pub type Result<T> = result::Result<T, Error>;
pub struct Error(Box<ErrorKind>);

impl Error {
/// A crate private constructor for `Error`.
pub(crate) fn new(kind: ErrorKind) -> Error {
Error(Box::new(kind))
}

/// Return the specific type of this error.
pub fn kind(&self) -> &ErrorKind {
&self.0
Expand Down Expand Up @@ -103,7 +101,7 @@ pub enum ErrorKind {

impl From<io::Error> for Error {
fn from(err: io::Error) -> Error {
new_error(ErrorKind::Io(err))
Error::new(ErrorKind::Io(err))
}
}

Expand All @@ -114,21 +112,7 @@ impl From<Error> for io::Error {
}

impl StdError for Error {
fn description(&self) -> &str {
match *self.0 {
ErrorKind::Io(ref err) => err.description(),
ErrorKind::Utf8 { ref err, .. } => err.description(),
ErrorKind::UnequalLengths { .. } => {
"record of different length found"
}
ErrorKind::Seek => "headers unavailable on seeked CSV reader",
ErrorKind::Serialize(ref err) => err,
ErrorKind::Deserialize { ref err, .. } => err.description(),
_ => unreachable!(),
}
}

fn cause(&self) -> Option<&dyn StdError> {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match *self.0 {
ErrorKind::Io(ref err) => Some(err),
ErrorKind::Utf8 { ref err, .. } => Some(err),
Expand Down Expand Up @@ -218,12 +202,12 @@ pub struct FromUtf8Error {
err: Utf8Error,
}

/// Create a new FromUtf8Error.
pub fn new_from_utf8_error(rec: ByteRecord, err: Utf8Error) -> FromUtf8Error {
FromUtf8Error { record: rec, err: err }
}

impl FromUtf8Error {
/// Create a new FromUtf8Error.
pub(crate) fn new(rec: ByteRecord, err: Utf8Error) -> FromUtf8Error {
FromUtf8Error { record: rec, err: err }
}

/// Access the underlying `ByteRecord` that failed UTF-8 validation.
pub fn into_byte_record(self) -> ByteRecord {
self.record
Expand All @@ -242,10 +226,7 @@ impl fmt::Display for FromUtf8Error {
}

impl StdError for FromUtf8Error {
fn description(&self) -> &str {
self.err.description()
}
fn cause(&self) -> Option<&dyn StdError> {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
Some(&self.err)
}
}
Expand Down Expand Up @@ -281,11 +262,7 @@ impl Utf8Error {
}
}

impl StdError for Utf8Error {
fn description(&self) -> &str {
"invalid utf-8 in CSV record"
}
}
impl StdError for Utf8Error {}

impl fmt::Display for Utf8Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Expand All @@ -309,15 +286,15 @@ pub struct IntoInnerError<W> {
err: io::Error,
}

/// Creates a new `IntoInnerError`.
///
/// (This is a visibility hack. It's public in this module, but not in the
/// crate.)
pub fn new_into_inner_error<W>(wtr: W, err: io::Error) -> IntoInnerError<W> {
IntoInnerError { wtr: wtr, err: err }
}

impl<W> IntoInnerError<W> {
/// Creates a new `IntoInnerError`.
///
/// (This is a visibility hack. It's public in this module, but not in the
/// crate.)
pub(crate) fn new(wtr: W, err: io::Error) -> IntoInnerError<W> {
IntoInnerError { wtr: wtr, err: err }
}

/// Returns the error which caused the call to `into_inner` to fail.
///
/// This error was returned when attempting to flush the internal buffer.
Expand All @@ -334,14 +311,9 @@ impl<W> IntoInnerError<W> {
}
}

impl<W: ::std::any::Any> StdError for IntoInnerError<W> {
fn description(&self) -> &str {
self.err.description()
}

#[allow(deprecated)]
fn cause(&self) -> Option<&dyn StdError> {
self.err.cause()
impl<W: std::any::Any> StdError for IntoInnerError<W> {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
self.err.source()
}
}

Expand Down

0 comments on commit 0c7005f

Please sign in to comment.