Skip to main content

substrate_data/forms/
source.rs

1//! A source file as it's kept and as it's read: on disk the binary form
2//! (what an editor may save), to people its text — formatted as editors
3//! write it, so a line in an error is the line the editor shows. A file
4//! still in text is read as it is.
5
6pub use super::read_error::ReadError;
7use crate::binary::{self, MAGIC};
8use crate::text::SyntaxError;
9
10/// Whether `bytes` are the binary form.
11#[must_use]
12pub fn is_binary(bytes: &[u8]) -> bool {
13    bytes.starts_with(MAGIC)
14}
15
16/// A source file's text: its binary form written out, or its text as it is.
17///
18/// # Errors
19///
20/// [`ReadError`] when the text isn't UTF-8 or the binary form is malformed.
21pub fn text(bytes: &[u8]) -> Result<String, ReadError> {
22    if !is_binary(bytes) {
23        return crate::utf8::from_utf8(bytes)
24            .map(str::to_owned)
25            .map_err(ReadError::NotUtf8);
26    }
27    let value = binary::decode(bytes).map_err(ReadError::Binary)?;
28    Ok(format!("{}\n", crate::patch::format(&value, 0)))
29}
30
31/// Text as a source file keeps it: binary, its comments kept as notes
32/// ([`crate::text::with_comments`]).
33///
34/// # Errors
35///
36/// [`SyntaxError`] when the text doesn't parse.
37pub fn binary(text: &str) -> Result<Vec<u8>, SyntaxError> {
38    crate::text::with_comments(text).map(|v| binary::encode(&v))
39}
40
41#[cfg(test)]
42mod tests {
43    use super::*;
44
45    #[test]
46    fn a_source_round_trips_through_its_binary_form() {
47        let text = "{\n  // Long.\n  pages: 3,\n  cover: \"@file:cover.png\"\n}";
48        let bytes = binary(text).unwrap();
49        assert!(is_binary(&bytes));
50        let shown = super::text(&bytes).unwrap();
51        assert!(
52            shown.contains("$pages") && shown.contains("@file:cover.png"),
53            "{shown}"
54        );
55        assert_eq!(
56            binary(&shown).unwrap(),
57            bytes,
58            "its text is the same file again"
59        );
60        assert_eq!(
61            super::text(text.as_bytes()).unwrap(),
62            text,
63            "text stays text"
64        );
65    }
66}