1use std::ops::Range;
2
3use anyhow::Result;
4use serde_derive::Serialize;
5use wasmparser::{KnownCustom, Parser, Payload::*};
6
7use crate::{
8 Authors, ComponentNames, Description, Homepage, Licenses, Metadata, ModuleNames, Producers,
9 Revision, Source,
10};
11
12#[derive(Debug, Serialize)]
18#[serde(rename_all = "lowercase")]
19pub enum Payload {
20 Component {
22 metadata: Metadata,
24 children: Vec<Payload>,
26 },
27 Module(Metadata),
29}
30
31impl Payload {
32 pub fn from_binary(input: &[u8]) -> Result<Self> {
35 let mut output = Vec::new();
36
37 for payload in Parser::new(0).parse_all(&input) {
38 match payload? {
39 Version { encoding, .. } => {
40 if output.is_empty() {
41 match encoding {
42 wasmparser::Encoding::Module => {
43 output.push(Self::empty_module(0..input.len()))
44 }
45 wasmparser::Encoding::Component => {
46 output.push(Self::empty_component(0..input.len()))
47 }
48 }
49 }
50 }
51 ModuleSection {
52 unchecked_range: range,
53 ..
54 } => output.push(Self::empty_module(range)),
55 ComponentSection {
56 unchecked_range: range,
57 ..
58 } => output.push(Self::empty_component(range)),
59 End { .. } => {
60 let finished = output.pop().expect("non-empty metadata stack");
61 if output.is_empty() {
62 return Ok(finished);
63 } else {
64 output.last_mut().unwrap().push_child(finished);
65 }
66 }
67 CustomSection(c) => match c.as_known() {
68 KnownCustom::Name(_) => {
69 let names = ModuleNames::from_bytes(c.data(), c.data_offset())?;
70 if let Some(name) = names.get_name() {
71 output
72 .last_mut()
73 .expect("non-empty metadata stack")
74 .metadata_mut()
75 .name = Some(name.clone());
76 }
77 }
78 KnownCustom::ComponentName(_) => {
79 let names = ComponentNames::from_bytes(c.data(), c.data_offset())?;
80 if let Some(name) = names.get_name() {
81 output
82 .last_mut()
83 .expect("non-empty metadata stack")
84 .metadata_mut()
85 .name = Some(name.clone());
86 }
87 }
88 KnownCustom::Producers(_) => {
89 let producers = Producers::from_bytes(c.data(), c.data_offset())?;
90 output
91 .last_mut()
92 .expect("non-empty metadata stack")
93 .metadata_mut()
94 .producers = Some(producers);
95 }
96 KnownCustom::Unknown if c.name() == "authors" => {
97 let a = Authors::parse_custom_section(&c)?;
98 let Metadata {
99 authors: author, ..
100 } = output
101 .last_mut()
102 .expect("non-empty metadata stack")
103 .metadata_mut();
104 *author = Some(a);
105 }
106 KnownCustom::Unknown if c.name() == "description" => {
107 let a = Description::parse_custom_section(&c)?;
108 let Metadata { description, .. } = output
109 .last_mut()
110 .expect("non-empty metadata stack")
111 .metadata_mut();
112 *description = Some(a);
113 }
114 KnownCustom::Unknown if c.name() == "licenses" => {
115 let a = Licenses::parse_custom_section(&c)?;
116 let Metadata { licenses, .. } = output
117 .last_mut()
118 .expect("non-empty metadata stack")
119 .metadata_mut();
120 *licenses = Some(a);
121 }
122 KnownCustom::Unknown if c.name() == "source" => {
123 let a = Source::parse_custom_section(&c)?;
124 let Metadata { source, .. } = output
125 .last_mut()
126 .expect("non-empty metadata stack")
127 .metadata_mut();
128 *source = Some(a);
129 }
130 KnownCustom::Unknown if c.name() == "homepage" => {
131 let a = Homepage::parse_custom_section(&c)?;
132 let Metadata { homepage, .. } = output
133 .last_mut()
134 .expect("non-empty metadata stack")
135 .metadata_mut();
136 *homepage = Some(a);
137 }
138 KnownCustom::Unknown if c.name() == "revision" => {
139 let a = Revision::parse_custom_section(&c)?;
140 let Metadata { revision, .. } = output
141 .last_mut()
142 .expect("non-empty metadata stack")
143 .metadata_mut();
144 *revision = Some(a);
145 }
146 KnownCustom::Unknown if c.name() == "version" => {
147 let a = crate::Version::parse_custom_section(&c)?;
148 let Metadata { version, .. } = output
149 .last_mut()
150 .expect("non-empty metadata stack")
151 .metadata_mut();
152 *version = Some(a);
153 }
154 _ => {}
155 },
156 _ => {}
157 }
158 }
159 Err(anyhow::anyhow!(
160 "malformed wasm binary, should have reached end"
161 ))
162 }
163
164 pub fn metadata(&self) -> &Metadata {
166 match self {
167 Payload::Component { metadata, .. } => metadata,
168 Payload::Module(metadata) => metadata,
169 }
170 }
171
172 pub fn metadata_mut(&mut self) -> &mut Metadata {
174 match self {
175 Payload::Component { metadata, .. } => metadata,
176 Payload::Module(metadata) => metadata,
177 }
178 }
179
180 fn empty_component(range: Range<usize>) -> Self {
181 let mut this = Self::Component {
182 metadata: Metadata::default(),
183 children: vec![],
184 };
185 this.metadata_mut().range = range;
186 this
187 }
188
189 fn empty_module(range: Range<usize>) -> Self {
190 let mut this = Self::Module(Metadata::default());
191 this.metadata_mut().range = range;
192 this
193 }
194
195 fn push_child(&mut self, child: Self) {
196 match self {
197 Self::Module { .. } => panic!("module shouldnt have children"),
198 Self::Component { children, .. } => children.push(child),
199 }
200 }
201}