1 | use std::borrow::Cow; |
2 | use std::fmt::{self, Display}; |
3 | use std::str::FromStr; |
4 | |
5 | use anyhow::{ensure, Error, Result}; |
6 | use serde::Serialize; |
7 | use wasm_encoder::{ComponentSection, CustomSection, Encode, Section}; |
8 | use wasmparser::CustomSectionReader; |
9 | |
10 | /// Contact details of the people or organization responsible, |
11 | /// encoded as a freeform string. |
12 | #[derive (Debug, Clone, PartialEq)] |
13 | pub struct Author(CustomSection<'static>); |
14 | |
15 | impl Author { |
16 | /// Create a new instance of `Author`. |
17 | pub fn new<S: Into<Cow<'static, str>>>(s: S) -> Self { |
18 | Self(CustomSection { |
19 | name: "author" .into(), |
20 | data: match s.into() { |
21 | Cow::Borrowed(s: &str) => Cow::Borrowed(s.as_bytes()), |
22 | Cow::Owned(s: String) => 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() == "author" , |
31 | "The `author` custom section should have a name of 'author'" |
32 | ); |
33 | let data: String = String::from_utf8(vec:reader.data().to_owned())?; |
34 | Ok(Self::new(data)) |
35 | } |
36 | } |
37 | |
38 | impl FromStr for Author { |
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 | |
46 | impl Serialize for Author { |
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 | |
55 | impl Display for Author { |
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 = String::from_utf8(self.0.data.to_vec()).unwrap(); |
60 | write!(f, " {data}" ) |
61 | } |
62 | } |
63 | |
64 | impl ComponentSection for Author { |
65 | fn id(&self) -> u8 { |
66 | ComponentSection::id(&self.0) |
67 | } |
68 | } |
69 | |
70 | impl Section for Author { |
71 | fn id(&self) -> u8 { |
72 | Section::id(&self.0) |
73 | } |
74 | } |
75 | |
76 | impl Encode for Author { |
77 | fn encode(&self, sink: &mut Vec<u8>) { |
78 | self.0.encode(sink); |
79 | } |
80 | } |
81 | |
82 | #[cfg (test)] |
83 | mod 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(&Author::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 = Author::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 = Author::new("Chashu Cat" ); |
108 | let json = serde_json::to_string(&author).unwrap(); |
109 | assert_eq!(r#""Chashu Cat""# , json); |
110 | } |
111 | } |
112 | |