diff --git a/src/lib.rs b/src/lib.rs index 83a9c577..cee8953d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -71,6 +71,9 @@ type CowStr<'s> = std::borrow::Cow<'s, str>; /// /// The output can be written to either a [`std::fmt::Write`] or a [`std::io::Write`] object. /// +/// If ownership of the [`Event`]s cannot be given to the renderer, use [`Render::push_ref`] or +/// [`Render::write_ref`]. +/// /// An implementor needs to at least implement the [`Render::render_event`] function that renders a /// single event to the output. If anything needs to be rendered at the beginning or end of the /// output, the [`Render::render_prologue`] and [`Render::render_epilogue`] can be implemented as @@ -130,7 +133,7 @@ pub trait Render { self.render_epilogue(&mut out) } - /// Write [`Event`]s to a byte sink, encoded as UTF-8. + /// Write owned [`Event`]s to a byte sink, encoded as UTF-8. /// /// NOTE: This performs many small writes, so IO writes should be buffered with e.g. /// [`std::io::BufWriter`]. @@ -139,29 +142,59 @@ pub trait Render { I: Iterator>, W: io::Write, { - struct Adapter { - inner: T, - error: io::Result<()>, - } + let mut out = WriteAdapter { + inner: out, + error: Ok(()), + }; - impl fmt::Write for Adapter { - fn write_str(&mut self, s: &str) -> fmt::Result { - match self.inner.write_all(s.as_bytes()) { - Ok(()) => Ok(()), - Err(e) => { - self.error = Err(e); - Err(fmt::Error) - } - } - } + match self.push(events, &mut out) { + Ok(()) => Ok(()), + Err(_) => match out.error { + Err(_) => out.error, + _ => Err(io::Error::new(io::ErrorKind::Other, "formatter error")), + }, } + } + + /// Push borrowed [`Event`]s to a unicode-accepting buffer or stream. + /// + /// # Examples + /// + /// Render a borrowed slice of [`Event`]s. + /// ``` + /// # use jotdown::Render; + /// # let events: &[jotdown::Event] = &[]; + /// let mut output = String::new(); + /// let mut renderer = jotdown::html::Renderer::default(); + /// renderer.push_ref(events.iter(), &mut output); + /// ``` + fn push_ref<'s, E, I, W>(&mut self, mut events: I, mut out: W) -> fmt::Result + where + E: AsRef>, + I: Iterator, + W: fmt::Write, + { + self.render_prologue(&mut out)?; + events.try_for_each(|e| self.render_event(e.as_ref(), &mut out))?; + self.render_epilogue(&mut out) + } - let mut out = Adapter { + /// Write borrowed [`Event`]s to a byte sink, encoded as UTF-8. + /// + /// NOTE: This performs many small writes, so IO writes should be buffered with e.g. + /// [`std::io::BufWriter`]. + fn write_ref<'s, E, I, W>(&mut self, events: I, out: W) -> io::Result<()> + where + E: AsRef>, + I: Iterator, + W: io::Write, + { + let mut out = WriteAdapter { inner: out, error: Ok(()), }; - match self.push(events, &mut out) { + match self.push_ref(events, &mut out) { Ok(()) => Ok(()), Err(_) => match out.error { Err(_) => out.error, @@ -171,6 +204,30 @@ pub trait Render { } } +struct WriteAdapter { + inner: T, + error: io::Result<()>, +} + +impl fmt::Write for WriteAdapter { + fn write_str(&mut self, s: &str) -> fmt::Result { + match self.inner.write_all(s.as_bytes()) { + Ok(()) => Ok(()), + Err(e) => { + self.error = Err(e); + Err(fmt::Error) + } + } + } +} + +// XXX why is this not a blanket implementation? +impl<'s> AsRef> for &Event<'s> { + fn as_ref(&self) -> &Event<'s> { + self + } +} + /// A Djot event. /// /// A Djot document is represented by a sequence of events. An element may consist of one or