wasm_metadata/oci_annotations/
authors.rs

1use std::borrow::Cow;
2use std::fmt::{self, Display};
3use std::str::FromStr;
4
5use anyhow::{ensure, Error, Result};
6use serde::Serialize;
7use wasm_encoder::{ComponentSection, CustomSection, Encode, Section};
8use wasmparser::CustomSectionReader;
9
10/// Contact details of the people or organization responsible,
11/// encoded as a freeform string.
12#[derive(Debug, Clone, PartialEq)]
13pub struct Authors(CustomSection<'static>);
14
15impl Authors {
16    /// Create a new instance of `Author`.
17    pub fn new<S: Into<Cow<'static, str>>>(s: S) -> Self {
18        Self(CustomSection {
19            name: "authors".into(),
20            data: match s.into() {
21                Cow::Borrowed(s) => Cow::Borrowed(s.as_bytes()),
22                Cow::Owned(s) => Cow::Owned(s.into()),
23            },
24        })
25    }
26
27    /// Parse an `author` custom section from a wasm binary.
28    pub(crate) fn parse_custom_section(reader: &CustomSectionReader<'_>) -> Result<Self> {
29        ensure!(
30            reader.name() == "authors",
31            "The `authors` custom section should have a name of 'authors'"
32        );
33        let data = String::from_utf8(reader.data().to_owned())?;
34        Ok(Self::new(data))
35    }
36}
37
38impl FromStr for Authors {
39    type Err = Error;
40
41    fn from_str(s: &str) -> Result<Self, Self::Err> {
42        Ok(Self::new(s.to_owned()))
43    }
44}
45
46impl Serialize for Authors {
47    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
48    where
49        S: serde::Serializer,
50    {
51        serializer.serialize_str(&self.to_string())
52    }
53}
54
55impl Display for Authors {
56    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57        // NOTE: this will never panic since we always guarantee the data is
58        // encoded as utf8, even if we internally store it as [u8].
59        let data = String::from_utf8(self.0.data.to_vec()).unwrap();
60        write!(f, "{data}")
61    }
62}
63
64impl ComponentSection for Authors {
65    fn id(&self) -> u8 {
66        ComponentSection::id(&self.0)
67    }
68}
69
70impl Section for Authors {
71    fn id(&self) -> u8 {
72        Section::id(&self.0)
73    }
74}
75
76impl Encode for Authors {
77    fn encode(&self, sink: &mut Vec<u8>) {
78        self.0.encode(sink);
79    }
80}
81
82#[cfg(test)]
83mod test {
84    use super::*;
85    use wasm_encoder::Component;
86    use wasmparser::Payload;
87
88    #[test]
89    fn roundtrip() {
90        let mut component = Component::new();
91        component.section(&Authors::new("Nori Cat"));
92        let component = component.finish();
93
94        let mut parsed = false;
95        for section in wasmparser::Parser::new(0).parse_all(&component) {
96            if let Payload::CustomSection(reader) = section.unwrap() {
97                let author = Authors::parse_custom_section(&reader).unwrap();
98                assert_eq!(author.to_string(), "Nori Cat");
99                parsed = true;
100            }
101        }
102        assert!(parsed);
103    }
104
105    #[test]
106    fn serialize() {
107        let author = Authors::new("Chashu Cat");
108        let json = serde_json::to_string(&author).unwrap();
109        assert_eq!(r#""Chashu Cat""#, json);
110    }
111}