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