diff --git a/RELEASING.md b/RELEASING.md index 42e23f40..2976e6e8 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -1,4 +1,3 @@ - # Releasing 1. Update the version number in [Cargo.toml](./Cargo.toml) diff --git a/examples/count.rs b/examples/count.rs index 730305c2..50f54d55 100644 --- a/examples/count.rs +++ b/examples/count.rs @@ -6,8 +6,7 @@ use las::{Read, Reader}; fn main() { let path = std::env::args() - .skip(1) - .next() + .nth(1) .expect("Must provide a path to a las file"); let mut reader = Reader::from_path(path).expect("Unable to open reader"); let npoints = reader diff --git a/src/error.rs b/src/error.rs index c7d83cb7..4aff1023 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,36 +1,67 @@ -use crate::{header, point, reader, vlr, writer, Transform, Version}; -use std::{io, str}; +use crate::{point::Format, Transform, Version}; use thiserror::Error; /// Crate-specific error enum. #[derive(Error, Debug)] +#[non_exhaustive] pub enum Error { - /// Feature is not supported by version. - #[error("feature {feature} is not supported by version {version}")] - #[allow(missing_docs)] - Feature { - version: Version, - feature: &'static str, - }, + /// The writer is closed. + #[error("the writer is closed")] + ClosedWriter, - /// A wrapper around `las::header::Error`. - #[error(transparent)] - Header(#[from] header::Error), + /// The header size, as computed, is too large. + #[error("the header is too large ({0} bytes) to convert to a raw header")] + HeaderTooLarge(usize), + + /// An invalid classification number. + #[error("invalid classification: {0}")] + InvalidClassification(u8), + + /// The file signature is not LASF. + #[error("the file signature is not 'LASF': {0:?}")] + InvalidFileSignature([u8; 4]), /// The value can't have the inverse transform applied. #[error("the transform {transform} cannot be inversely applied to {n}")] - #[allow(missing_docs)] - InverseTransform { n: f64, transform: Transform }, + InvalidInverseTransform { + /// The float. + n: f64, - /// Wrapper around `std::io::Error`. + /// The transform that can't be applied + transform: Transform, + }, + + /// This is an invalid point format. + /// + /// It has a combination of options that can't exist. + #[error("invalid point format: {0}")] + InvalidPointFormat(Format), + + /// This is an invalid format number. + #[error("invalid format number: {0}")] + InvalidPointFormatNumber(u8), + + /// This is not a valid scanner channel + #[error("invalid scanner channel: {0}")] + InvalidScannerChannel(u8), + + /// [std::io::Error] #[error(transparent)] - Io(#[from] io::Error), + Io(#[from] std::io::Error), /// The las data is laszip compressed. - #[error( - "the las data is laszip compressed, but laszip compression is not supported by this build" - )] - Laszip, + #[error("the las data is laszip compressed, but the las crate is not built with laz support")] + LaszipNotEnabled, + + /// [laz::LasZipError] + #[cfg(feature = "laz")] + #[error(transparent)] + LasZipError(#[from] laz::LasZipError), + + /// The laszip vlr was not found, the points cannot be decompressed. + #[cfg(feature = "laz")] + #[error("laszip vlr not found")] + LasZipVlrNotFound, /// This string is not ASCII. #[error("this string is not ascii: {0}")] @@ -40,45 +71,107 @@ pub enum Error { #[error("the bytes are not zero-filled: {0:?}")] NotZeroFilled(Vec), - /// Wrapper around `las::point::Error`. - #[error(transparent)] - Point(#[from] point::Error), + /// The offset to the start of the evlrs is too small. + #[error("offset to the start of the evlrs is too small: {0}")] + OffsetToEvlrsTooSmall(u64), - /// Wrapper around `las::reader::Error`. - #[error(transparent)] - Reader(#[from] reader::Error), + /// The offset to point data is too large. + #[error("the offset to the point data is too large: {0}")] + OffsetToPointDataTooLarge(usize), + + /// The offset to the point data was too small. + #[error("offset to the point data is too small: {0}")] + OffsetToPointDataTooSmall(u32), + + /// Overlap points are handled by an attribute on [Point](crate::Point), not by a classification. + #[error("overlap points are handled by the `is_overlap` member of `las::Point`, not by classifications")] + OverlapClassification, + + /// The attributes of the point format and point do not match. + #[error("the attributes of the point format ({0}) do not match the point")] + PointAttributesDoNotMatch(Format), + + /// The point data record length is too small for the format. + #[error("the point data record length {len} is too small for format {format}")] + PointDataRecordLengthTooLarge { + /// The point format. + format: Format, + + /// The length of the point data record. + len: u16, + }, + + /// Point padding is only allowed when evlrs are present. + #[error("point padding is only allowed when evlrs are present")] + PointPaddingNotAllowed, + + /// This is not a valid return number. + #[error("invalid return number {return_number} for version {version:?}")] + ReturnNumber { + /// The return number. + return_number: u8, + + /// The version that doesn't support this return number. + version: Option, + }, /// This string is too long for the target slice. #[error("string is too long for a slice of length {len}: {string}")] - #[allow(missing_docs)] - StringTooLong { string: String, len: usize }, + StringTooLong { + /// The string. + string: String, - /// Wrapper around `std::str::Utf8Error`. - #[error(transparent)] - Utf8(#[from] str::Utf8Error), + /// The target length. + len: usize, + }, - /// Wrapper around `las::writer::Error`. - #[error(transparent)] - Writer(#[from] Box), + /// Too many extended variable length records. + #[error("too many extended variable length records: {0}")] + TooManyEvlrs(usize), - /// Wrapper around `las::vlr::Error`. - #[error(transparent)] - Vlr(#[from] vlr::Error), + /// Too many points for this version. + #[error("too many points for version {version}: {n}")] + TooManyPoints { + /// The number of points. + n: u64, - /// Wrapper around `laz::LasZipError` - #[cfg(feature = "laz")] - #[error("laszip error: {0}")] - LasZipError(laz::LasZipError), + /// The LAS version + version: Version, + }, - /// The Laszip vlr was not found, the points cannot be decompressed - #[cfg(feature = "laz")] - #[error("laszip vlr not found")] - LasZipVlrNotFound, -} + /// Too many variable length records. + #[error("too many variable length records: {0}")] + TooManyVlrs(usize), + + /// Feature is not supported by version. + #[error("feature {feature} is not supported by version {version}")] + UnsupportedFeature { + /// The LAS version. + version: Version, + + /// The feature that is not supported + feature: &'static str, + }, + + /// The point format is not supported by version. + #[error("version {version} does not support format {format}")] + UnsupportedFormat { + /// The LAS version. + version: Version, + + /// The unsupported point format. + format: Format, + }, + + /// [std::str::Utf8Error] + #[error(transparent)] + Utf8(#[from] std::str::Utf8Error), + + /// Wkt is required for this point format. + #[error("wkt is required for this point format: {0}")] + WktRequired(Format), -#[cfg(feature = "laz")] -impl From for Error { - fn from(error: laz::LasZipError) -> Error { - Error::LasZipError(error) - } + /// The vlr data is too long. + #[error("the vlr is too long: {0}")] + VlrTooLong(usize), } diff --git a/src/header/builder.rs b/src/header/builder.rs index 6651bbae..2fa6b355 100644 --- a/src/header/builder.rs +++ b/src/header/builder.rs @@ -98,11 +98,10 @@ impl Builder { let n = point_format.len(); match raw_header.point_data_record_length.cmp(&n) { Ordering::Less => { - return Err(Error::PointDataRecordLength { + return Err(Error::PointDataRecordLengthTooLarge { format: point_format, len: raw_header.point_data_record_length, - } - .into()) + }) } Ordering::Equal => {} // pass Ordering::Greater => point_format.extra_bytes = raw_header.point_data_record_length - n, @@ -197,11 +196,10 @@ impl Builder { } // TODO check waveforms if !self.version.supports_point_format(self.point_format) { - return Err(Error::Format { + return Err(Error::UnsupportedFormat { version: self.version, format: self.point_format, - } - .into()); + }); } let mut vlrs = Vec::new(); let mut evlrs = Vec::new(); @@ -222,7 +220,7 @@ impl Builder { if !evlrs.is_empty() { self.version.verify_support_for::()?; } else if !self.point_padding.is_empty() { - return Err(Error::PointPadding.into()); + return Err(Error::PointPaddingNotAllowed); } let header = Header { bounds: self.bounds, diff --git a/src/header/mod.rs b/src/header/mod.rs index d04597a0..71b9f714 100644 --- a/src/header/mod.rs +++ b/src/header/mod.rs @@ -61,8 +61,8 @@ pub use self::builder::Builder; use crate::{ - point::Format, raw, utils::FromLasStr, Bounds, GpsTimeType, Point, Result, Transform, Vector, - Version, Vlr, + point::Format, raw, utils::FromLasStr, Bounds, Error, GpsTimeType, Point, Result, Transform, + Vector, Version, Vlr, }; use chrono::{Datelike, NaiveDate, Utc}; use std::{collections::HashMap, iter::Chain, slice::Iter}; @@ -71,57 +71,6 @@ use uuid::Uuid; mod builder; -/// Header-specific errors. -#[derive(Clone, Copy, Debug, Error)] -pub enum Error { - /// The file signature is not LASF. - #[error("the file signature is not 'LASF': {0:?}")] - FileSignature([u8; 4]), - - /// The point format is not supported by version. - #[error("version {version} does not support format {format}")] - #[allow(missing_docs)] - Format { version: Version, format: Format }, - - /// The offset to point data is too large. - #[error("the offset to the point data is too large: {0}")] - OffsetToPointDataTooLarge(usize), - - /// The point data record length is too small for the format. - #[error("the point data record length {len} is too small for format {format}")] - #[allow(missing_docs)] - PointDataRecordLength { format: Format, len: u16 }, - - /// Point padding is only allowed when evlrs are present. - #[error("point padding is only allowed when evlrs are present")] - PointPadding, - - /// The header size, as computed, is too large. - #[error("the header is too large ({0} bytes) to convert to a raw header")] - TooLarge(usize), - - /// Too many extended variable length records. - #[error("too many extended variable length records: {0}")] - TooManyEvlrs(usize), - - /// Too many points for this version. - #[error("too many points for version {version}: {n}")] - #[allow(missing_docs)] - TooManyPoints { n: u64, version: Version }, - - /// Too many variable length records. - #[error("too many variable length records: {0}")] - TooManyVlrs(usize), - - /// The header size, as provided by the raw header, is too small. - #[error("the header is too small ({0} bytes)")] - TooSmall(u16), - - /// Wkt is required for this point format. - #[error("wkt is required for this point format: {0}")] - WktRequired(Format), -} - /// Metadata describing the layout, source, and interpretation of the points. /// /// Headers include *all* las metadata, including regular and extended variable length records and @@ -582,7 +531,7 @@ impl Header { fn header_size(&self) -> Result { let header_size = self.version.header_size() as usize + self.padding.len(); if header_size > u16::MAX as usize { - Err(Error::TooLarge(header_size).into()) + Err(Error::HeaderTooLarge(header_size)) } else { Ok(header_size as u16) } @@ -592,7 +541,7 @@ impl Header { let vlr_len = self.vlrs.iter().fold(0, |acc, vlr| acc + vlr.len(false)); let offset = self.header_size()? as usize + vlr_len + self.vlr_padding.len(); if offset > u32::MAX as usize { - Err(Error::OffsetToPointDataTooLarge(offset).into()) + Err(Error::OffsetToPointDataTooLarge(offset)) } else { Ok(offset as u32) } @@ -601,7 +550,7 @@ impl Header { fn number_of_variable_length_records(&self) -> Result { let n = self.vlrs().len(); if n > u32::MAX as usize { - Err(Error::TooManyVlrs(n).into()) + Err(Error::TooManyVlrs(n)) } else { Ok(n as u32) } @@ -617,8 +566,7 @@ impl Header { Err(Error::TooManyPoints { n: self.number_of_points, version: self.version, - } - .into()) + }) } } else { Ok(self.number_of_points as u32) @@ -632,11 +580,10 @@ impl Header { for (&i, &n) in &self.number_of_points_by_return { if i > 5 { if !self.version.supports::() { - return Err(crate::point::Error::ReturnNumber { + return Err(Error::ReturnNumber { return_number: i, version: Some(self.version), - } - .into()); + }); } } else if i > 0 { if n > u64::from(u32::MAX) { @@ -644,8 +591,7 @@ impl Header { return Err(Error::TooManyPoints { n, version: self.version, - } - .into()); + }); } } else { number_of_points_by_return[i as usize - 1] = n as u32; @@ -660,7 +606,7 @@ impl Header { if n == 0 { Ok(None) } else if n > u32::MAX as usize { - Err(Error::TooManyEvlrs(n).into()) + Err(Error::TooManyEvlrs(n)) } else { let start_of_first_evlr = self.point_data_len() + self.point_padding.len() as u64 @@ -676,11 +622,10 @@ impl Header { let mut number_of_points_by_return = [0; 15]; for (&i, &n) in &self.number_of_points_by_return { if i > 15 { - return Err(crate::point::Error::ReturnNumber { + return Err(Error::ReturnNumber { return_number: i, version: Some(self.version), - } - .into()); + }); } else if i > 0 { number_of_points_by_return[i as usize - 1] = n; } diff --git a/src/point/classification.rs b/src/point/classification.rs index 328bd7d4..3f94a62b 100644 --- a/src/point/classification.rs +++ b/src/point/classification.rs @@ -80,7 +80,7 @@ impl Classification { 9 => Classification::Water, 10 => Classification::Rail, 11 => Classification::RoadSurface, - 12 => return Err(Error::OverlapClassification.into()), + 12 => return Err(Error::OverlapClassification), 13 => Classification::WireGuard, 14 => Classification::WireConductor, 15 => Classification::TransmissionTower, diff --git a/src/point/format.rs b/src/point/format.rs index e9918edf..f12db66b 100644 --- a/src/point/format.rs +++ b/src/point/format.rs @@ -92,7 +92,7 @@ impl Format { pub fn new(n: u8) -> Result { let is_compressed = is_point_format_compressed(n); if n > 10 && !is_compressed { - Err(Error::FormatNumber(n).into()) + Err(Error::InvalidPointFormatNumber(n)) } else { let n = point_format_id_compressed_to_uncompressd(n); Ok(Format { @@ -172,7 +172,7 @@ impl Format { /// ``` pub fn to_u8(&self) -> Result { if !cfg!(feature = "laz") && self.is_compressed { - Err(Error::Format(*self).into()) + Err(Error::InvalidPointFormat(*self)) } else if self.is_extended { if self.has_gps_time { if self.has_color { @@ -183,22 +183,22 @@ impl Format { Ok(8) } } else if self.has_waveform { - Err(Error::Format(*self).into()) + Err(Error::InvalidPointFormat(*self)) } else { Ok(7) } } else if self.has_nir { - Err(Error::Format(*self).into()) + Err(Error::InvalidPointFormat(*self)) } else if self.has_waveform { Ok(9) } else { Ok(6) } } else { - Err(Error::Format(*self).into()) + Err(Error::InvalidPointFormat(*self)) } } else if self.has_nir { - Err(Error::Format(*self).into()) + Err(Error::InvalidPointFormat(*self)) } else if self.has_waveform { if self.has_gps_time { if self.has_color { @@ -207,7 +207,7 @@ impl Format { Ok(4) } } else { - Err(Error::Format(*self).into()) + Err(Error::InvalidPointFormat(*self)) } } else { let mut n = if self.has_gps_time { 1 } else { 0 }; diff --git a/src/point/mod.rs b/src/point/mod.rs index 9ba29564..90c00bca 100644 --- a/src/point/mod.rs +++ b/src/point/mod.rs @@ -17,43 +17,9 @@ mod format; mod scan_direction; pub use self::{classification::Classification, format::Format, scan_direction::ScanDirection}; -use crate::{raw, raw::point::Waveform, Color, Result, Transform, Vector}; +use crate::{raw, raw::point::Waveform, Color, Error, Result, Transform, Vector}; use thiserror::Error; -/// Point-specific errors -#[derive(Debug, Clone, Copy, Error)] -pub enum Error { - /// An invalid classification number. - #[error("invalid classification: {0}")] - Classification(u8), - - /// This is an invalid format. - /// - /// It has a combination of options that can't exist. - #[error("invalid format: {0}")] - Format(Format), - - /// This is an invalid format number. - #[error("invalid format number: {0}")] - FormatNumber(u8), - - /// Overlap points are handled by an attribute on [Point], not by a classification. - #[error("overlap points are handled by the `is_overlap` member of `las::Point`, not by classifications")] - OverlapClassification, - - /// This is not a valid return number. - #[error("invalid return number {return_number} for version {version:?}")] - #[allow(missing_docs)] - ReturnNumber { - return_number: u8, - version: Option, - }, - - /// This is not a valid scanner channel - #[error("invalid scanner channel: {0}")] - ScannerChannel(u8), -} - /// A three dimensional point. #[derive(Clone, Debug, Default, PartialEq)] pub struct Point { @@ -219,16 +185,14 @@ impl Point { Err(Error::ReturnNumber { return_number: self.return_number, version: None, - } - .into()) + }) } else if self.number_of_returns > 15 { Err(Error::ReturnNumber { return_number: self.number_of_returns, version: None, - } - .into()) + }) } else if self.scanner_channel > 3 { - Err(Error::ScannerChannel(self.scanner_channel).into()) + Err(Error::InvalidScannerChannel(self.scanner_channel)) } else { let a = (self.number_of_returns << 4) + self.return_number; let mut b = self.scanner_channel << 4; diff --git a/src/raw/header.rs b/src/raw/header.rs index 864c92bc..4cc4829f 100644 --- a/src/raw/header.rs +++ b/src/raw/header.rs @@ -3,7 +3,7 @@ use crate::{ feature::{Evlrs, LargeFiles, Waveforms}, raw::LASF, - Result, Version, + utils, Error, Result, Version, }; use byteorder::{LittleEndian, ReadBytesExt}; use std::io::{Read, Write}; @@ -255,12 +255,10 @@ impl Header { /// let header = Header::read_from(&mut file).unwrap(); /// ``` pub fn read_from(mut read: R) -> Result
{ - use crate::{header::Error, utils}; - let mut header = Header::default(); read.read_exact(&mut header.file_signature)?; if header.file_signature != LASF { - return Err(Error::FileSignature(header.file_signature).into()); + return Err(Error::InvalidFileSignature(header.file_signature)); } header.file_source_id = read.read_u16::()?; header.global_encoding = read.read_u16::()?; diff --git a/src/raw/point.rs b/src/raw/point.rs index 55feba58..6772e551 100644 --- a/src/raw/point.rs +++ b/src/raw/point.rs @@ -1,8 +1,8 @@ //! Defines raw las points and some enums required to handle the various point formats. use crate::{ - point::{Classification, Error, Format, ScanDirection}, - Color, Result, + point::{Classification, Format, ScanDirection}, + Color, Error, Result, }; use std::io::{Read, Write}; @@ -665,18 +665,16 @@ impl Flags { Err(Error::ReturnNumber { return_number: self.return_number(), version: None, - } - .into()) + }) } else if self.number_of_returns() > 7 { Err(Error::ReturnNumber { return_number: self.number_of_returns(), version: None, - } - .into()) + }) } else if c > 31 { - Err(Error::Classification(c).into()) + Err(Error::InvalidClassification(c)) } else if self.scanner_channel() > 0 { - Err(Error::ScannerChannel(self.scanner_channel()).into()) + Err(Error::InvalidScannerChannel(self.scanner_channel())) } else { let mut a = (self.number_of_returns() << 3) + self.return_number(); if self.scan_direction() == ScanDirection::LeftToRight { diff --git a/src/reader.rs b/src/reader.rs index c9947706..f1cdb48d 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -19,18 +19,6 @@ //! let reader = Reader::from_path("tests/data/autzen.las").unwrap(); //! ``` //! -//! Compressed files are supported when using the feature "laz": -//! -//! ``` -//! use las::Reader; -//! if cfg!(feature = "laz") { -//! assert!(Reader::from_path("tests/data/autzen.laz").is_ok()); -//! } else { -//! assert!(Reader::from_path("tests/data/autzen.laz").is_err()); -//! } -//! -//! ``` -//! //! Use `Reader::read` to read one point, and `Reader::points` to get an iterator over //! `Result`: //! @@ -40,10 +28,30 @@ //! let first_point = reader.read().unwrap().unwrap(); //! let the_rest = reader.points().map(|r| r.unwrap()).collect::>(); //! ``` +//! +//! # Compression +//! +//! [lazip](https://laszip.org/) is supported by enabling the `laz` feature in your `Cargo.toml`: +//! +//! ```toml +//! [dependencies] +//! las = { version = "*", features = ["laz"] } +//! ``` +//! +//! Then: +//! +//! ``` +//! # #[cfg(feature = "laz")] +//! # { +//! use las::Reader; +//! let reader = Reader::from_path("tests/data/autzen.laz").unwrap(); +//! # } +//! ``` +//! #[cfg(feature = "laz")] use crate::laz::CompressedPointReader; -use crate::{raw, Builder, Header, Point, Result, Vlr}; +use crate::{raw, Builder, Error, Header, Point, Result, Vlr}; use std::{ cmp::Ordering, fmt::Debug, @@ -51,19 +59,6 @@ use std::{ io::{BufReader, Seek, SeekFrom}, path::Path, }; -use thiserror::Error; - -/// Error while reading. -#[derive(Error, Clone, Copy, Debug)] -pub enum Error { - /// The offset to the point data was too small. - #[error("offset to the point data is too small: {0}")] - OffsetToPointDataTooSmall(u32), - - /// The offset to the start of the evlrs is too small. - #[error("offset to the start of the evlrs is too small: {0}")] - OffsetToEvlrsTooSmall(u64), -} #[inline] pub(crate) fn read_point_from(source: &mut R, header: &Header) -> Result { @@ -242,7 +237,7 @@ impl<'a> Reader<'a> { let mut builder = Builder::new(raw_header)?; if !cfg!(feature = "laz") && builder.point_format.is_compressed { - return Err(crate::Error::Laszip); + return Err(Error::LaszipNotEnabled); } for _ in 0..number_of_variable_length_records { @@ -259,7 +254,9 @@ impl<'a> Reader<'a> { } Ordering::Equal => {} // pass Ordering::Greater => { - return Err(Error::OffsetToPointDataTooSmall(offset_to_point_data as u32).into()) + return Err(Error::OffsetToPointDataTooSmall( + offset_to_point_data as u32, + )) } } @@ -280,7 +277,7 @@ impl<'a> Reader<'a> { if !builder.point_format.is_compressed { match evlr.start_of_first_evlr.cmp(&offset_to_end_of_points) { Ordering::Less => { - return Err(Error::OffsetToEvlrsTooSmall(evlr.start_of_first_evlr).into()); + return Err(Error::OffsetToEvlrsTooSmall(evlr.start_of_first_evlr)); } Ordering::Equal => {} // pass Ordering::Greater => { @@ -393,7 +390,7 @@ impl<'a> Reader<'a> { /// ``` pub fn from_path>(path: P) -> Result> { File::open(path) - .map_err(crate::Error::from) + .map_err(Error::from) .and_then(|file| Reader::new(BufReader::new(file))) } } diff --git a/src/transform.rs b/src/transform.rs index b2dd9f28..0113ce07 100644 --- a/src/transform.rs +++ b/src/transform.rs @@ -54,7 +54,7 @@ impl Transform { let n = round((n - self.offset) / self.scale, r); if n > f64::from(i32::MAX) || n < f64::from(i32::MIN) { - Err(Error::InverseTransform { + Err(Error::InvalidInverseTransform { n, transform: *self, }) diff --git a/src/version.rs b/src/version.rs index 429f93d3..c06a4175 100644 --- a/src/version.rs +++ b/src/version.rs @@ -79,7 +79,7 @@ impl Version { if self.supports::() { Ok(()) } else { - Err(Error::Feature { + Err(Error::UnsupportedFeature { version: *self, feature: F::name(), }) diff --git a/src/vlr.rs b/src/vlr.rs index 63fc6423..6efee6c5 100644 --- a/src/vlr.rs +++ b/src/vlr.rs @@ -29,20 +29,11 @@ //! assert_eq!(1, header.vlrs().len()); //! ``` -use crate::{raw, Result}; -use thiserror::Error; +use crate::{raw, Error, Result}; const REGULAR_HEADER_SIZE: usize = 54; const EXTENDED_HEADER_SIZE: usize = 60; -/// Vlr-specific errors. -#[derive(Error, Debug, Clone, Copy)] -pub enum Error { - /// The vlr data is too long. - #[error("the vlr is too long: {0}")] - TooLong(usize), -} - /// A variable length record. #[derive(Clone, Debug, Default, PartialEq)] pub struct Vlr { @@ -164,7 +155,7 @@ impl Vlr { if is_extended { Ok(raw::vlr::RecordLength::Evlr(self.data.len() as u64)) } else if self.data.len() > u16::MAX as usize { - Err(Error::TooLong(self.data.len()).into()) + Err(Error::VlrTooLong(self.data.len())) } else { Ok(raw::vlr::RecordLength::Vlr(self.data.len() as u16)) } diff --git a/src/writer.rs b/src/writer.rs index bb346ba5..09dd0e0e 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -33,31 +33,13 @@ #[cfg(feature = "laz")] use crate::laz::CompressedPointWriter; -use crate::{point::Format, Header, Point, Result}; +use crate::{Error, Header, Point, Result}; use std::{ fmt::Debug, fs::File, io::{BufWriter, Cursor, Seek, SeekFrom}, path::Path, }; -use thiserror::Error; - -/// Writer errors. -#[derive(Error, Debug)] -pub enum Error { - /// The writer is closed. - #[error("the writer is closed")] - Closed, - - /// The attributes of the point format and point do not match. - #[error("the attributes of the point format ({format}) do not match the point: {point:?}")] - #[allow(missing_docs)] - PointAttributes { format: Format, point: Point }, - - /// Wrapper around `std::io::Error`. - #[error(transparent)] - Io(#[from] std::io::Error), -} pub(crate) fn write_point_to( dst: W, @@ -267,7 +249,7 @@ impl Writer { /// ``` pub fn close(&mut self) -> Result<()> { if self.closed { - return Err(Box::new(Error::Closed).into()); + return Err(Error::ClosedWriter); } self.point_writer.done()?; @@ -313,14 +295,12 @@ impl Write for Writer { /// Writes a point. fn write(&mut self, point: Point) -> Result<()> { if self.closed { - return Err(Box::new(Error::Closed).into()); + return Err(Error::ClosedWriter); } if !point.matches(self.header().point_format()) { - return Err(Box::new(Error::PointAttributes { - format: *self.header().point_format(), - point, - }) - .into()); + return Err(Error::PointAttributesDoNotMatch( + *self.header().point_format(), + )); } self.point_writer.write_next(point) } @@ -386,7 +366,7 @@ impl Writer> { header.point_format_mut().is_compressed = compress; File::create(path) - .map_err(crate::Error::from) + .map_err(Error::from) .and_then(|file| Writer::new(BufWriter::new(file), header)) } } diff --git a/tests/autzen.rs b/tests/autzen.rs index 689276c6..1cc51346 100644 --- a/tests/autzen.rs +++ b/tests/autzen.rs @@ -126,7 +126,7 @@ fn test_read_n_on(path: &str) { let mut all_points = Vec::with_capacity(reader.header().number_of_points() as usize); loop { let mut points = reader.read_n(n).unwrap(); - if points.len() == 0 { + if points.is_empty() { break; } all_points.append(&mut points);