1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
//! Handling of the wasm `producers` section
//!
//! Specified upstream at
//! https://github.com/WebAssembly/tool-conventions/blob/master/ProducersSection.md

use crate::emit::{Emit, EmitContext};
use crate::error::Result;
use crate::module::Module;

/// Representation of the wasm custom section `producers`
#[derive(Debug, Default)]
pub struct ModuleProducers {
    fields: Vec<Field>,
}

#[derive(Debug)]
struct Field {
    name: String,
    values: Vec<Value>,
}

#[derive(Debug)]
struct Value {
    name: String,
    version: String,
}

impl ModuleProducers {
    /// Adds a new `language` (versioned) to the producers section
    pub fn add_language(&mut self, language: &str, version: &str) {
        self.field("language", language, version);
    }

    /// Adds a new `processed-by` (versioned) to the producers section
    pub fn add_processed_by(&mut self, tool: &str, version: &str) {
        self.field("processed-by", tool, version);
    }

    /// Adds a new `sdk` (versioned) to the producers section
    pub fn add_sdk(&mut self, sdk: &str, version: &str) {
        self.field("sdk", sdk, version);
    }

    fn field(&mut self, field_name: &str, name: &str, version: &str) {
        let new_value = Value {
            name: name.to_string(),
            version: version.to_string(),
        };
        for field in self.fields.iter_mut() {
            if field.name != field_name {
                continue;
            }

            for value in field.values.iter_mut() {
                if value.name == name {
                    *value = new_value;
                    return;
                }
            }
            field.values.push(new_value);
            return;
        }
        self.fields.push(Field {
            name: field_name.to_string(),
            values: vec![new_value],
        })
    }

    /// Clear the producers section of all keys/values
    pub fn clear(&mut self) {
        self.fields.truncate(0);
    }
}

impl Module {
    /// Parse a producers section from the custom section payload specified.
    pub(crate) fn parse_producers_section(
        &mut self,
        data: wasmparser::ProducersSectionReader,
    ) -> Result<()> {
        log::debug!("parse producers section");

        for field in data {
            let field = field?;
            let mut values = Vec::new();
            for value in field.get_producer_field_values_reader()? {
                let value = value?;
                values.push(Value {
                    name: value.name.to_string(),
                    version: value.version.to_string(),
                });
            }
            let name = field.name.to_string();
            self.producers.fields.push(Field { name, values });
        }

        Ok(())
    }
}

impl Emit for ModuleProducers {
    fn emit(&self, cx: &mut EmitContext) {
        log::debug!("emit producers section");
        if self.fields.len() > 0 {
            cx.custom_section("producers").list(&self.fields);
        }
    }
}

impl Emit for Field {
    fn emit(&self, cx: &mut EmitContext) {
        cx.encoder.str(&self.name);
        cx.list(&self.values);
    }
}

impl Emit for Value {
    fn emit(&self, cx: &mut EmitContext) {
        cx.encoder.str(&self.name);
        cx.encoder.str(&self.version);
    }
}