diff --git a/src/to_wkt/mod.rs b/src/to_wkt/mod.rs index 3581c8b..7e3e5b6 100644 --- a/src/to_wkt/mod.rs +++ b/src/to_wkt/mod.rs @@ -8,6 +8,35 @@ pub use geo_trait_impl::{ write_rect, write_triangle, }; +use crate::error::Error; +use std::io; + +/// A wrapper around something that implements std::io::Write to be used with our writer traits, +/// which require std::fmt::Write +struct WriterWrapper { + writer: W, + most_recent_err: Option, +} + +impl WriterWrapper { + fn new(writer: W) -> Self { + Self { + writer, + most_recent_err: None, + } + } +} + +impl std::fmt::Write for WriterWrapper { + fn write_str(&mut self, s: &str) -> std::fmt::Result { + self.writer.write(s.as_bytes()).map_err(|err| { + self.most_recent_err = Some(err); + std::fmt::Error + })?; + Ok(()) + } +} + /// A trait for converting values to WKT pub trait ToWkt where @@ -49,7 +78,44 @@ where /// /// assert_eq!(wkt_string, "POINT(1.2 3.4)"); /// ``` - fn write_wkt(&self, mut writer: impl std::io::Write) -> std::io::Result<()> { - writer.write_all(self.wkt_string().as_bytes()) + fn write_wkt(&self, writer: impl io::Write) -> io::Result<()> { + let mut writer_wrapper = WriterWrapper::new(writer); + write_geometry(&mut writer_wrapper, &self.to_wkt()).map_err(|err| { + match (err, writer_wrapper.most_recent_err) { + (Error::FmtError(_), Some(io_err)) => io_err, + (Error::FmtError(fmt_err), None) => { + debug_assert!(false, "FmtError without setting an error on WriterWrapper"); + io::Error::new(io::ErrorKind::Other, fmt_err.to_string()) + } + (other, _) => io::Error::new(io::ErrorKind::Other, other.to_string()), + } + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[cfg(feature = "geo-types")] + #[test] + fn write_wkt_error_handling() { + struct FailingWriter; + impl io::Write for FailingWriter { + fn write(&mut self, _buf: &[u8]) -> io::Result { + Err(io::Error::new( + io::ErrorKind::Other, + "FailingWriter always fails", + )) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } + } + + let point = geo_types::Point::new(1.2, 3.4); + let err = point.write_wkt(FailingWriter).unwrap_err(); + assert_eq!(err.to_string(), "FailingWriter always fails"); } }