Skip to main content

yog_data/
source.rs

1//! A source file as it's kept and as it's read: on disk binary Yog Data
2//! (what the editor saves), to people its text — formatted as Yog's 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
6use crate::binary::{self, MAGIC};
7use crate::text::SyntaxError;
8
9/// Whether `bytes` are binary Yog Data.
10pub fn is_binary(bytes: &[u8]) -> bool {
11    bytes.starts_with(MAGIC)
12}
13
14/// A source file's text: its binary form written out, or its text as it is.
15pub fn text(bytes: &[u8]) -> Result<String, String> {
16    if !is_binary(bytes) {
17        return String::from_utf8(bytes.to_vec()).map_err(|e| e.to_string());
18    }
19    let value = binary::decode(bytes).map_err(|e| e.to_string())?;
20    Ok(format!("{}\n", crate::patch::format(&value, 0)))
21}
22
23/// Text as a source file keeps it: binary, its comments kept as notes
24/// ([`crate::text::with_comments`]).
25pub fn binary(text: &str) -> Result<Vec<u8>, SyntaxError> {
26    crate::text::with_comments(text).map(|v| binary::encode(&v))
27}
28
29#[cfg(test)]
30mod tests {
31    use super::*;
32
33    #[test]
34    fn a_source_round_trips_through_its_binary_form() {
35        let text = "{\n  // Hard.\n  hardness: 3,\n  drop: \"@item:ruby\"\n}";
36        let bytes = binary(text).unwrap();
37        assert!(is_binary(&bytes));
38        let shown = super::text(&bytes).unwrap();
39        assert!(
40            shown.contains("$hardness") && shown.contains("@item:ruby"),
41            "{shown}"
42        );
43        assert_eq!(
44            binary(&shown).unwrap(),
45            bytes,
46            "its text is the same file again"
47        );
48        assert_eq!(
49            super::text(text.as_bytes()).unwrap(),
50            text,
51            "text stays text"
52        );
53    }
54}