Skip to main content

ephemeris_documents/
source.rs

1//! The current source of a document, decoded once.
2
3use std::borrow::Cow;
4use std::fmt::Display;
5use std::str;
6
7use crate::error::DocumentError;
8use crate::line_ending::{LineEnding, LineEndingSpec};
9
10/// The current source of a document and the line ending to write.
11#[derive(Debug)]
12pub(crate) struct Source<'a> {
13    text: Option<Cow<'a, str>>,
14    line_ending: LineEnding,
15}
16
17impl<'a> Source<'a> {
18    /// Decode `current` and resolve the line ending of `spec`.
19    ///
20    /// The bytes are only read when they can matter, which is under partial
21    /// ownership or to preserve their line ending. The text is only kept
22    /// under partial ownership, with its line endings changed to LF.
23    ///
24    /// # Errors
25    /// Returns an error for invalid UTF-8 and for a current source whose
26    /// line endings cannot be resolved.
27    pub(crate) fn read(
28        current: Option<&'a [u8]>,
29        spec: LineEndingSpec,
30        partial: bool,
31    ) -> Result<Self, DocumentError> {
32        let text = if partial || spec == LineEndingSpec::Preserve {
33            current.map(str::from_utf8).transpose()?
34        } else {
35            None
36        };
37        Ok(Self {
38            line_ending: spec.resolve(text)?,
39            text: text.filter(|_| partial).map(LineEnding::normalise),
40        })
41    }
42
43    /// The current text with LF line endings, when it is kept.
44    pub(crate) fn text(&self) -> Option<&str> {
45        self.text.as_deref()
46    }
47
48    /// Render `document` with the resolved line ending.
49    pub(crate) fn write(&self, document: &impl Display) -> Vec<u8> {
50        self.line_ending.write(document).into_bytes()
51    }
52}