1 use crate::MemoryIndex;
2 use crate::component::Transcode;
3 use crate::fact::core_types::CoreTypes;
4 use crate::prelude::*;
5 use wasm_encoder::{EntityType, ValType};
6 
7 #[derive(Copy, Clone, Hash, Eq, PartialEq)]
8 pub struct Transcoder {
9     pub from_memory: MemoryIndex,
10     pub from_memory64: bool,
11     pub to_memory: MemoryIndex,
12     pub to_memory64: bool,
13     pub op: Transcode,
14 }
15 
16 impl Transcoder {
name(&self) -> String17     pub fn name(&self) -> String {
18         format!(
19             "{} (mem{} => mem{})",
20             self.op.desc(),
21             self.from_memory.as_u32(),
22             self.to_memory.as_u32(),
23         )
24     }
25 
ty(&self, types: &mut CoreTypes) -> EntityType26     pub fn ty(&self, types: &mut CoreTypes) -> EntityType {
27         let from_ptr = if self.from_memory64 {
28             ValType::I64
29         } else {
30             ValType::I32
31         };
32         let to_ptr = if self.to_memory64 {
33             ValType::I64
34         } else {
35             ValType::I32
36         };
37 
38         let ty = match self.op {
39             // These direct transcodings take the source pointer, the source
40             // code units, and the destination pointer.
41             //
42             // The memories being copied between are part of each intrinsic and
43             // the destination code units are the same as the source.
44             // Note that the pointers are dynamically guaranteed to be aligned
45             // and in-bounds for the code units length as defined by the string
46             // encoding.
47             Transcode::Copy(_) | Transcode::Latin1ToUtf16 => {
48                 types.function(&[from_ptr, from_ptr, to_ptr], &[])
49             }
50 
51             // Transcoding from utf8 to utf16 takes the from ptr/len as well as
52             // a destination. The destination is valid for len*2 bytes. The
53             // return value is how many code units were written to the
54             // destination.
55             Transcode::Utf8ToUtf16 => types.function(&[from_ptr, from_ptr, to_ptr], &[to_ptr]),
56 
57             // Transcoding to utf8 as a smaller format takes all the parameters
58             // and returns the amount of space consumed in the src/destination
59             Transcode::Utf16ToUtf8 | Transcode::Latin1ToUtf8 => {
60                 types.function(&[from_ptr, from_ptr, to_ptr, to_ptr], &[from_ptr, to_ptr])
61             }
62 
63             // The return type is a tagged length which indicates which was
64             // used
65             Transcode::Utf16ToCompactProbablyUtf16 => {
66                 types.function(&[from_ptr, from_ptr, to_ptr], &[to_ptr])
67             }
68 
69             // The initial step of transcoding from a fixed format to a compact
70             // format. Takes the ptr/len of the source the destination
71             // pointer. The destination length is implicitly the same. Returns
72             // how many code units were consumed in the source, which is also
73             // how many bytes were written to the destination.
74             Transcode::Utf8ToLatin1 | Transcode::Utf16ToLatin1 => {
75                 types.function(&[from_ptr, from_ptr, to_ptr], &[from_ptr, to_ptr])
76             }
77 
78             // The final step of transcoding to a compact format when the fixed
79             // transcode has failed. This takes the ptr/len of the source that's
80             // remaining to transcode. Then this takes the destination ptr/len
81             // as well as the destination bytes written so far with latin1.
82             // Finally this returns the number of code units written to the
83             // destination.
84             Transcode::Utf8ToCompactUtf16 | Transcode::Utf16ToCompactUtf16 => {
85                 types.function(&[from_ptr, from_ptr, to_ptr, to_ptr, to_ptr], &[to_ptr])
86             }
87         };
88         EntityType::Function(ty)
89     }
90 }
91