diff --git a/sailfish/src/runtime/filter.rs b/sailfish/src/runtime/filter.rs index eb57d21..b79bbe9 100644 --- a/sailfish/src/runtime/filter.rs +++ b/sailfish/src/runtime/filter.rs @@ -70,7 +70,7 @@ impl<'a, T: Render> Render for Upper<'a, T> { let content = b .as_str() .get(old_len..) - .ok_or_else(|| RenderError::new("buffer size shrinked while rendering"))?; + .ok_or_else(|| RenderError::BufSize)?; let s = content.to_uppercase(); unsafe { b._set_len(old_len) }; b.push_str(&*s); @@ -107,7 +107,7 @@ impl<'a, T: Render> Render for Lower<'a, T> { let content = b .as_str() .get(old_len..) - .ok_or_else(|| RenderError::new("buffer size shrinked while rendering"))?; + .ok_or_else(|| RenderError::BufSize)?; let s = content.to_lowercase(); unsafe { b._set_len(old_len) }; b.push_str(&*s); @@ -166,7 +166,7 @@ fn trim_impl(b: &mut Buffer, old_len: usize) -> Result<(), RenderError> { let new_contents = b .as_str() .get(old_len..) - .ok_or_else(|| RenderError::new("buffer size shrinked while rendering"))?; + .ok_or_else(|| RenderError::BufSize)?; let trimmed = new_contents.trim(); let trimmed_len = trimmed.len(); @@ -243,7 +243,7 @@ fn truncate_impl( let new_contents = b .as_str() .get(old_len..) - .ok_or_else(|| RenderError::new("buffer size shrinked while rendering"))?; + .ok_or_else(|| RenderError::BufSize)?; if let Some(idx) = new_contents.char_indices().nth(limit).map(|(i, _)| i) { unsafe { b._set_len(old_len.wrapping_add(idx)) }; diff --git a/sailfish/src/runtime/mod.rs b/sailfish/src/runtime/mod.rs index b163c2b..0b1857a 100644 --- a/sailfish/src/runtime/mod.rs +++ b/sailfish/src/runtime/mod.rs @@ -10,79 +10,9 @@ mod macros; mod render; mod size_hint; -pub use buffer::*; -pub use render::*; -pub use size_hint::*; - -use std::fmt; +pub use buffer::Buffer; +pub use render::{Render, RenderError, RenderResult}; +pub use size_hint::SizeHint; #[doc(hidden)] pub use crate::{render, render_escaped, render_noop, render_text}; - -#[derive(Clone, Debug)] -enum RenderErrorKind { - Msg(String), - Fmt(fmt::Error), -} - -/// The error type which is returned from template function -#[derive(Clone, Debug)] -pub struct RenderError { - // currently RenderError simply wraps the fmt::Error - kind: RenderErrorKind, -} - -impl RenderError { - /// Construct a new error with custom message - pub fn new(msg: &str) -> Self { - Self { - kind: RenderErrorKind::Msg(msg.to_owned()), - } - } -} - -impl fmt::Display for RenderError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.kind { - RenderErrorKind::Msg(ref s) => f.write_str(&**s), - RenderErrorKind::Fmt(ref e) => fmt::Display::fmt(e, f), - } - } -} - -impl std::error::Error for RenderError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self.kind { - RenderErrorKind::Msg(_) => None, - RenderErrorKind::Fmt(ref e) => Some(e), - } - } -} - -impl From for RenderError { - #[inline] - fn from(other: fmt::Error) -> Self { - Self { - kind: RenderErrorKind::Fmt(other), - } - } -} - -/// Result type returned from `TemplateOnce::render_once` method -pub type RenderResult = Result; - -#[cfg(test)] -mod tests { - use super::*; - use std::error::Error; - - #[test] - fn render_error() { - let err = RenderError::new("custom error"); - assert!(err.source().is_none()); - assert_eq!(format!("{}", err), "custom error"); - - let err = RenderError::from(std::fmt::Error::default()); - assert!(err.source().is_some()); - } -} diff --git a/sailfish/src/runtime/render.rs b/sailfish/src/runtime/render.rs index 6980718..2cf9dd9 100644 --- a/sailfish/src/runtime/render.rs +++ b/sailfish/src/runtime/render.rs @@ -1,5 +1,6 @@ use std::borrow::Cow; use std::cell::{Ref, RefMut}; +use std::fmt; use std::num::{ NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping, @@ -9,7 +10,7 @@ use std::rc::Rc; use std::sync::{Arc, MutexGuard, RwLockReadGuard, RwLockWriteGuard}; use super::buffer::Buffer; -use super::{escape, RenderError}; +use super::escape; /// types which can be rendered inside buffer block (`<%= %>`) /// @@ -361,9 +362,62 @@ impl Render for Wrapping { } } +/// The error type which is returned from template function +#[derive(Clone, Debug)] +pub enum RenderError { + /// Custom error message + Msg(String), + /// fmt::Error was raised during rendering + Fmt(fmt::Error), + /// Buffer size shrinked during rendering + /// + /// This method won't be raised unless you implement `Render` trait for custom type. + /// + /// Also there is no guarentee that this error will be returned whenever the buffer + /// size shrinked. + BufSize, +} + +impl RenderError { + /// Construct a new error with custom message + pub fn new(msg: &str) -> Self { + RenderError::Msg(msg.to_owned()) + } +} + +impl fmt::Display for RenderError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + RenderError::Msg(ref s) => f.pad(&**s), + RenderError::Fmt(ref e) => fmt::Display::fmt(e, f), + RenderError::BufSize => f.pad("buffer size shrinked while rendering"), + } + } +} + +impl std::error::Error for RenderError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + RenderError::Msg(_) | RenderError::BufSize => None, + RenderError::Fmt(ref e) => Some(e), + } + } +} + +impl From for RenderError { + #[inline] + fn from(other: fmt::Error) -> Self { + RenderError::Fmt(other) + } +} + +/// Result type returned from `TemplateOnce::render_once` method +pub type RenderResult = Result; + #[cfg(test)] mod tests { use super::*; + use std::error::Error; #[test] fn receiver_coercion() { @@ -430,4 +484,14 @@ mod tests { Render::render_escaped(&std::f32::NAN, &mut b).unwrap(); assert_eq!(b.as_str(), "0.0inf-infNaN"); } + + #[test] + fn render_error() { + let err = RenderError::new("custom error"); + assert!(err.source().is_none()); + assert_eq!(format!("{}", err), "custom error"); + + let err = RenderError::from(std::fmt::Error::default()); + assert!(err.source().is_some()); + } }