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 #[cfg(feature = "oci")]
97 KnownCustom::Unknown if c.name() == "authors" => {
98 let a = Authors::parse_custom_section(&c)?;
99 let Metadata { authors, .. } = output
100 .last_mut()
101 .expect("non-empty metadata stack")
102 .metadata_mut();
103 *authors = Some(a);
104 }
105 #[cfg(feature = "oci")]
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 #[cfg(feature = "oci")]
115 KnownCustom::Unknown if c.name() == "licenses" => {
116 let a = Licenses::parse_custom_section(&c)?;
117 let Metadata { licenses, .. } = output
118 .last_mut()
119 .expect("non-empty metadata stack")
120 .metadata_mut();
121 *licenses = Some(a);
122 }
123 #[cfg(feature = "oci")]
124 KnownCustom::Unknown if c.name() == "source" => {
125 let a = Source::parse_custom_section(&c)?;
126 let Metadata { source, .. } = output
127 .last_mut()
128 .expect("non-empty metadata stack")
129 .metadata_mut();
130 *source = Some(a);
131 }
132 #[cfg(feature = "oci")]
133 KnownCustom::Unknown if c.name() == "homepage" => {
134 let a = Homepage::parse_custom_section(&c)?;
135 let Metadata { homepage, .. } = output
136 .last_mut()
137 .expect("non-empty metadata stack")
138 .metadata_mut();
139 *homepage = Some(a);
140 }
141 #[cfg(feature = "oci")]
142 KnownCustom::Unknown if c.name() == "revision" => {
143 let a = Revision::parse_custom_section(&c)?;
144 let Metadata { revision, .. } = output
145 .last_mut()
146 .expect("non-empty metadata stack")
147 .metadata_mut();
148 *revision = Some(a);
149 }
150 #[cfg(feature = "oci")]
151 KnownCustom::Unknown if c.name() == "version" => {
152 let a = crate::Version::parse_custom_section(&c)?;
153 let Metadata { version, .. } = output
154 .last_mut()
155 .expect("non-empty metadata stack")
156 .metadata_mut();
157 *version = Some(a);
158 }
159 #[cfg(feature = "oci")]
160 KnownCustom::Unknown if c.name() == ".dep-v0" => {
161 let a = crate::Dependencies::parse_custom_section(&c)?;
162 let Metadata { dependencies, .. } = output
163 .last_mut()
164 .expect("non-empty metadata stack")
165 .metadata_mut();
166 *dependencies = Some(a);
167 }
168 _ => {}
169 },
170 _ => {}
171 }
172 }
173 Err(anyhow::anyhow!(
174 "malformed wasm binary, should have reached end"
175 ))
176 }
177
178 pub fn metadata(&self) -> &Metadata {
180 match self {
181 Payload::Component { metadata, .. } => metadata,
182 Payload::Module(metadata) => metadata,
183 }
184 }
185
186 pub fn metadata_mut(&mut self) -> &mut Metadata {
188 match self {
189 Payload::Component { metadata, .. } => metadata,
190 Payload::Module(metadata) => metadata,
191 }
192 }
193
194 fn empty_component(range: Range<usize>) -> Self {
195 let mut this = Self::Component {
196 metadata: Metadata::default(),
197 children: vec![],
198 };
199 this.metadata_mut().range = range;
200 this
201 }
202
203 fn empty_module(range: Range<usize>) -> Self {
204 let mut this = Self::Module(Metadata::default());
205 this.metadata_mut().range = range;
206 this
207 }
208
209 fn push_child(&mut self, child: Self) {
210 match self {
211 Self::Module { .. } => panic!("module shouldnt have children"),
212 Self::Component { children, .. } => children.push(child),
213 }
214 }
215}