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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
use std::{
    cell::RefCell,
    sync::atomic::{AtomicU8, Ordering},
};

use anyhow::{Context, Error};
use original::SourceFile;
use wai_bindgen_rust::Handle;

wai_bindgen_rust::export!("wasmer-pack.exports.wai");

pub struct WasmerPack;

impl crate::wasmer_pack::WasmerPack for WasmerPack {}

pub struct Package(original::Package);

impl crate::wasmer_pack::Package for Package {
    fn new(
        metadata: Handle<Metadata>,
        libraries: Vec<wasmer_pack::Library>,
        commands: Vec<wasmer_pack::Command>,
    ) -> Handle<crate::Package> {
        let metadata = metadata.0.borrow().clone();
        let libraries = libraries.into_iter().map(|lib| lib.into()).collect();
        let commands = commands.into_iter().map(|cmd| cmd.into()).collect();
        let pkg = original::Package::new(metadata, libraries, commands);

        Handle::new(Package(pkg))
    }

    fn from_webc(bytes: Vec<u8>) -> Result<Handle<crate::Package>, wasmer_pack::Error> {
        let webc = webc::Container::from_bytes(bytes).context("Invalid webc")?;
        let pkg = original::Package::from_webc(&webc)?;
        Ok(Handle::new(Package(pkg)))
    }

    fn generate_javascript(
        &self,
        options: wasmer_pack::BindingsOptions,
    ) -> Result<Vec<wasmer_pack::File>, wasmer_pack::Error> {
        let original_options = original::BindingsOptions { name: options.name };
        let files = original::generate_javascript(&self.0, &original_options)?;
        Ok(unwrap_files(files))
    }

    fn generate_python(
        &self,
        options: wasmer_pack::BindingsOptions,
    ) -> Result<Vec<wasmer_pack::File>, wasmer_pack::Error> {
        let original_options = original::BindingsOptions { name: options.name };
        let files = original::generate_python(&self.0, &original_options)?;
        Ok(unwrap_files(files))
    }
}

fn unwrap_files(files: original::Files) -> Vec<wasmer_pack::File> {
    files
        .into_iter()
        .map(|(path, SourceFile(contents))| wasmer_pack::File {
            filename: path.display().to_string(),
            contents,
        })
        .collect()
}

pub struct Interface(original::Interface);

impl crate::wasmer_pack::Interface for Interface {
    fn from_wit(name: String, contents: String) -> Result<Handle<Interface>, wasmer_pack::Error> {
        let exports = original::Interface::from_wit(&name, &contents)?;
        Ok(Handle::new(Interface(exports)))
    }

    fn from_path(path: String) -> Result<Handle<Interface>, wasmer_pack::Error> {
        let exports = original::Interface::from_path(path)?;
        Ok(Handle::new(Interface(exports)))
    }
}

pub struct Metadata(RefCell<original::Metadata>);

impl crate::wasmer_pack::Metadata for Metadata {
    fn new(
        package_name: String,
        version: String,
    ) -> Result<Handle<crate::Metadata>, wasmer_pack::Error> {
        let meta = original::Metadata::new(package_name.parse()?, version);

        Ok(Handle::new(Metadata(RefCell::new(meta))))
    }

    fn set_description(&self, description: String) {
        self.0.borrow_mut().description = Some(description);
    }
}

impl From<crate::wasmer_pack::Abi> for original::Abi {
    fn from(abi: crate::wasmer_pack::Abi) -> Self {
        match abi {
            wasmer_pack::Abi::None => original::Abi::None,
            wasmer_pack::Abi::Wasi => original::Abi::Wasi,
        }
    }
}

impl From<Error> for crate::wasmer_pack::Error {
    fn from(e: Error) -> Self {
        crate::wasmer_pack::Error {
            message: e.to_string(),
            verbose: format!("{e:?}"),
            causes: e.chain().map(|e| e.to_string()).collect(),
        }
    }
}

impl From<wasmer_pack::Library> for original::Library {
    fn from(lib: wasmer_pack::Library) -> Self {
        let wasmer_pack::Library {
            exports,
            imports,
            abi,
            wasm,
        } = lib;
        original::Library {
            module: original::Module {
                name: format!("{}.wasm", exports.0.name()),
                abi: abi.into(),
                wasm,
            },
            exports: exports.0.clone(),
            imports: imports.iter().map(|i| i.0.clone()).collect(),
        }
    }
}

impl From<wasmer_pack::Command> for original::Command {
    fn from(cmd: wasmer_pack::Command) -> Self {
        let wasmer_pack::Command { name, wasm } = cmd;
        original::Command { name, wasm }
    }
}

// Something requires a RNG, so we provide our own dummy implementation
getrandom::register_custom_getrandom!(rand);

fn rand(buf: &mut [u8]) -> Result<(), getrandom::Error> {
    static NEXT: AtomicU8 = AtomicU8::new(0);

    for dest in buf {
        // Note: atomics wrap on overflow
        *dest = NEXT.fetch_add(1, Ordering::Relaxed);
    }

    Ok(())
}