рдкреНрд░рдХреНрд░рд┐рдпрд╛рддреНрдордХ рдореИрдХреНрд░реЛрдЬрд╝ рдХреЗ рд╡рд┐рднрд┐рдиреНрди рдкрд╣рд▓реБрдУрдВ рдкрд░ рдЕрдкрдиреЗ рд╢реЛрдз рдХреЛ рдЬрд╛рд░реА рд░рдЦрдиреЗ рдХреЗ рд╣рд┐рд╕реНрд╕реЗ рдХреЗ рд░реВрдк рдореЗрдВ, рдореИрдВ рдЙрдирдХреА рдХреНрд╖рдорддрд╛рдУрдВ рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╕рд╛рдЭрд╛ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВред рдЖрдкрдХреЛ рдпрд╛рдж рджрд┐рд▓рд╛ рджреВрдВ рдХрд┐ рдкреНрд░рдХреНрд░рд┐рдпрд╛рддреНрдордХ рдореИрдХреНрд░реЛрдЬрд╝ рдЖрдкрдХреЛ рднрд╛рд╖рд╛ рдореЗрдВ рдПрдХ рдореЗрдЯрд╛рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рддрддреНрд╡ рдЬреЛрдбрд╝рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ рдФрд░ рдЗрд╕ рддрд░рд╣ рдирд┐рдпрдорд┐рдд рд╕рдВрдЪрд╛рд▓рди, рдЬреИрд╕реЗ рдХрд┐ рдХреНрд░рдорд╛рдВрдХрди рдпрд╛ рдХреНрд╡реЗрд░реА рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХреЛ рд╕рд░рд▓ рдмрдирд╛рддрд╛ рд╣реИред рдЙрдирдХреЗ рдореВрд▓ рдореЗрдВ, рдореИрдХреНрд░реЛрдЬрд╝ рдХрдВрдкрд╛рдЗрд▓рд░ рдкреНрд▓рдЧрдЗрдиреНрд╕ рд╣реИрдВ рдЬреЛ рд░реИрдХ рдХреЗ рдирд┐рд░реНрдорд╛рдг рд╕реЗ рдкрд╣рд▓реЗ рд╕рдВрдХрд▓рд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдЬрд┐рд╕рдореЗрдВ рдЙрдирдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдРрд╕реЗ рдореИрдХреНрд░реЛ рдореЗрдВ рдХреБрдЫ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдХрдорд┐рдпрд╛рдВ рд╣реИрдВред
- рдЖрдИрдбреАрдИ рдореЗрдВ рдРрд╕реЗ рдореИрдХреНрд░реЛрдЬрд╝ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдиреЗ рдореЗрдВ рдХрдард┐рдирд╛рдИред рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдЖрдкрдХреЛ рдХрд┐рд╕реА рддрд░рд╣ рдЗрди рд╕рднреА рдореИрдХреНрд░реЛ рдХреЛ рд╕рдВрдХрд▓рд┐рдд рдХрд░рдиреЗ, рд▓реЛрдб рдХрд░рдиреЗ рдФрд░ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЛрдб рдПрдирд╛рд▓рд╛рдЗрдЬрд╝рд░ рдХреЛ рдкрдврд╝рд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рд╕рднреА рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХреЛ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦрддреЗ рд╣реБрдПред рдпрд╣ рдмрд╣реБрдд рд╣реА рдЧреИрд░-рддреБрдЪреНрдЫ рдХрд╛рд░реНрдп рд╣реИред
- рдЪреВрдВрдХрд┐ рдореИрдХреНрд░реЛрдЬрд╝ рдЖрддреНрдордирд┐рд░реНрднрд░ рд╣реИрдВ рдФрд░ рдПрдХ-рджреВрд╕рд░реЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреБрдЫ рдирд╣реАрдВ рдЬрд╛рдирддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рдореИрдХреНрд░реЛрдЬрд╝ рдХреА рд░рдЪрдирд╛ рдХрд░рдиреЗ рдХрд╛ рдХреЛрдИ рддрд░реАрдХрд╛ рдирд╣реАрдВ рд╣реИ, рдЬреЛ рдХрднреА-рдХрднреА рдЙрдкрдпреЛрдЧреА рд╣реЛ рд╕рдХрддрд╛ рд╣реИред
рдкрд╣рд▓реА рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, WASM рдореЙрдбреНрдпреВрд▓ рдореЗрдВ рд╕рднреА рдкреНрд░рдХреНрд░рд┐рдпрд╛рддреНрдордХ рдореИрдХреНрд░реЛрдЬрд╝ рдХреЗ рд╕рдВрдХрд▓рди рдХреЗ рд╕рд╛рде рдкреНрд░рдпреЛрдЧ рдХрд┐рдП рдЬрд╛ рд░рд╣реЗ рд╣реИрдВ , рдЬреЛ рднрд╡рд┐рд╖реНрдп рдореЗрдВ рдЙрдиреНрд╣реЗрдВ рд▓рдХреНрд╖реНрдп рдорд╢реАрди рдкрд░ рд╕рдВрдХрд▓рд┐рдд рдХрд░рдиреЗ рд╕реЗ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдордирд╛ рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реЛрдЧрд╛, рдФрд░ рд╕рд╛рде рд╣реА IDE рдореЗрдВ рдЙрдирдХреЗ рд╕рдорд░реНрдерди рд╕реЗ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдПред
рджреВрд╕рд░реА рд╕рдорд╕реНрдпрд╛ рдХреЗ рд░реВрдк рдореЗрдВ, рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдореИрдВ рд╕рд┐рд░реНрдл рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдкрдиреЗ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░рдиреЗ рдЬрд╛ рд░рд╣рд╛ рд╣реВрдВред рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рд╣рдореЗрдВ рдПрдХ рдореИрдХреНрд░реЛ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ рдЬреЛ рдХреБрдЫ рдЕрддрд┐рд░рд┐рдХреНрдд рдореИрдХреНрд░реЛрдЬрд╝ рдХреЛ рд▓реЛрдб рдХрд░рдиреЗ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдПрдХ рдкрд╛рдЗрдкрд▓рд╛рдЗрди рдореЗрдВ рд╕рдВрдпреЛрдЬрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреА рд╣реИред рд╕рдмрд╕реЗ рд╕рд░рд▓ рдорд╛рдорд▓реЗ рдореЗрдВ, рдЖрдк рдмрд╕ рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рдХреА рдХрд▓реНрдкрдирд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
рдорд╛рди рд▓реАрдЬрд┐рдП рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХреБрдЫ рдореИрдХреНрд░реЛ рд╣реИрдВ TextMessage
рдЬреЛ рдХрд┐рд╕реА рджрд┐рдП рдЧрдП рдкреНрд░рдХрд╛рд░ рдХреЗ рд▓рд┐рдП рд▓рдХреНрд╖рдг рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддреЗ рд╣реИрдВ ToString
рдФрд░ FromStr
рдХреБрдЫ рдХреЛрдбреЗрдХ рдХреЛ рдПрдХ рдкрд╛рдареАрдп рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдХреЗ рд░реВрдк рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред рд╡рд┐рднрд┐рдиреНрди рдкреНрд░рдХрд╛рд░ рдХреЗ рд╕рдВрджреЗрд╢реЛрдВ рдореЗрдВ рдПрдХ рдЕрд▓рдЧ рдХреЛрдбреЗрдХ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рдФрд░ рдЙрдирдХреА рдкреВрд░реА рд╕реВрдЪреА рд╕рдордп рдХреЗ рд╕рд╛рде рд╡рд┐рд╕реНрддрд╛рд░рд┐рдд рд╣реЛ рд╕рдХрддреА рд╣реИ, рдФрд░ рдкреНрд░рддреНрдпреЗрдХ рдХреЛрдбреЗрдХ рдХреЗ рдкрд╛рд╕ рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХрд╛ рдЕрдкрдирд╛ рдЕрдиреВрдард╛ рд╕реЗрдЯ рд╣реЛ рд╕рдХрддрд╛ рд╣реИред
#[derive(Debug, Serialize, Deserialize, PartialEq, TextMessage)]
#[text_message(codec = "serde_json", params(pretty))]
struct FooMessage {
name: String,
description: String,
value: u64,
}
, . libloading, IDE. , syn
quote
, , .
WASM , . .
, watt WASM , . watt proc-macro2
, . , darling
proc-macro2
, .
, proc-macro2
, WASM
- . , wasmtime, bytecodealliance, , Mozilla, Intel RedHat. wasmtime , , ,
Disclaimer: wasmtime ,
, , . WASM , .
!
, , , WASM , . .
:
pub fn implement_codec(input: TokenStream) -> TokenStream;
, , . TokenStream
, :
pub fn implement_codec(input: &str) -> String;
, ,
, :
, , ! WASM , , , , .
, , , . , , , , , . : .
#[no_mangle]
pub unsafe extern "C" fn toy_alloc(size: i32) -> i32 {
let size_bytes: [u8; 4] = size.to_le_bytes();
let mut buf: Vec<u8> = Vec::with_capacity(size as usize + size_bytes.len());
buf.extend(size_bytes.iter());
to_host_ptr(buf)
}
unsafe fn to_host_ptr(mut buf: Vec<u8>) -> i32 {
let ptr = buf.as_mut_ptr();
mem::forget(buf);
ptr as *mut c_void as usize as i32
}
#[no_mangle]
pub unsafe extern "C" fn toy_free(ptr: i32) {
let ptr = ptr as usize as *mut u8;
let mut size_bytes = [0u8; 4];
ptr.copy_to(size_bytes.as_mut_ptr(), 4);
let size = u32::from_le_bytes(size_bytes) as usize;
Vec::from_raw_parts(ptr, size, size);
}
, , wasm_bindgen
.
WASM . , .
#[no_mangle]
pub unsafe extern "C" fn implement_codec(
item_ptr: i32,
item_len: i32,
) -> i32 {
let item = str_from_raw_parts(item_ptr, item_len);
let item = TokenStream::from_str(&item).expect("Unable to parse item");
let tokens = codec::implement_codec(item);
let out = tokens.to_string();
to_host_buf(out)
}
pub unsafe fn str_from_raw_parts<'a>(ptr: i32, len: i32) -> &'a str {
let slice = std::slice::from_raw_parts(ptr as *const u8, len as usize);
std::str::from_utf8(slice).unwrap()
}
, WASM .
pub struct WasmMacro {
module: Module,
}
impl WasmMacro {
pub fn from_file(file: impl AsRef<Path>) -> anyhow::Result<Self> {
let store = Store::default();
let module = Module::from_file(&store, file)?;
Ok(Self { module })
}
pub fn proc_macro_derive(
&self,
fun: &str,
item: TokenStream,
) -> anyhow::Result<TokenStream> {
let item = item.to_string();
let instance = Instance::new(&self.module, &[])?;
let proc_macro_attribute_fn = instance
.get_export(fun)
.ok_or_else(|| anyhow!("Unable to find `{}` method in the export table", fun))?
.func()
.ok_or_else(|| anyhow!("export {} is not a function", fun))?
.get2::<i32, i32, i32,>()?;
let item_buf = WasmBuf::from_host_buf(&instance, item);
let (item_ptr, item_len) = item_buf.raw_parts();
let ptr = proc_macro_attribute_fn(item_ptr, item_len).unwrap();
let res = WasmBuf::from_raw_ptr(&instance, ptr);
let res_str = std::str::from_utf8(res.as_ref())?;
TokenStream::from_str(&res_str)
.map_err(|_| anyhow!("Unable to parse token stream"))
}
}
WasmBuf
: ,
, toy_alloc
.
, .
struct WasmBuf<'a> {
offset: usize,
len: usize,
instance: &'a Instance,
memory: &'a Memory,
}
const WASM_PTR_LEN: usize = 4;
impl<'a> WasmBuf<'a> {
pub fn new(instance: &'a Instance, len: usize) -> Self {
let memory = Self::get_memory(instance);
let offset = Self::toy_alloc(instance, len);
Self {
offset: offset as usize,
len,
instance,
memory,
}
}
pub fn from_host_buf(instance: &'a Instance, bytes: impl AsRef<[u8]>) -> Self {
let bytes = bytes.as_ref();
let len = bytes.len();
let mut wasm_buf = Self::new(instance, len);
wasm_buf.as_mut().copy_from_slice(bytes);
wasm_buf
}
pub fn from_raw_ptr(instance: &'a Instance, offset: i32) -> Self {
let offset = offset as usize;
let memory = Self::get_memory(instance);
let len = unsafe {
let buf = memory.data_unchecked();
let mut len_bytes = [0; WASM_PTR_LEN];
len_bytes.copy_from_slice(&buf[offset..offset + WASM_PTR_LEN]);
u32::from_le_bytes(len_bytes)
};
Self {
offset,
len: len as usize,
memory,
instance,
}
}
pub fn as_ref(&self) -> &[u8] {
unsafe {
let begin = self.offset + WASM_PTR_LEN;
let end = begin + self.len;
&self.memory.data_unchecked()[begin..end]
}
}
pub fn as_mut(&mut self) -> &mut [u8] {
unsafe {
let begin = self.offset + WASM_PTR_LEN;
let end = begin + self.len;
&mut self.memory.data_unchecked_mut()[begin..end]
}
}
}
, .
impl Drop for WasmBuf<'_> {
fn drop(&mut self) {
Self::toy_free(self.instance, self.len);
}
}
,
WASM , .
#[proc_macro_derive(TextMessage, attributes(text_message))]
pub fn text_message(input: TokenStream) -> TokenStream {
let input: DeriveInput = parse_macro_input!(input);
let attrs = TextMessageAttrs::from_raw(&input.attrs)
.expect("Unable to parse text message attributes.");
let codec_dir = Path::new(&std::env::var("CARGO_MANIFEST_DIR")
.unwrap())
.join("codecs");
let plugin_name = format!("{}_text_codec.wasm", attrs.codec);
let codec_path = codec_dir.join(plugin_name);
let wasm_macro = WasmMacro::from_file(codec_path)
.expect("Unable to load wasm module");
wasm_macro
.proc_macro_derive(
"implement_codec",
input.into_token_stream().into(),
)
.expect("Unable to apply proc_macro_attribute")
}
. , WASM , .
#[derive(Debug, Serialize, Deserialize, PartialEq, TextMessage)]
#[text_message(codec = "serde_json", params(pretty))]
struct FooMessage {
name: String,
description: String,
value: u64,
}
fn main() {
let msg = FooMessage {
name: "Linus Torvalds".to_owned(),
description: "The Linux founder.".to_owned(),
value: 1,
};
let text = msg.to_string();
println!("{}", text);
let msg2 = text.parse().unwrap();
assert_eq!(msg, msg2);
}
рдЬрдмрдХрд┐ рдпрд╣ рд░реЛрдЯреА рдХреА рд░реЛрдЯреА рд╕реЗ рдПрдХ рдЯреНрд░реЙрд▓реА рдХреА рддрд░рд╣ рдЕрдзрд┐рдХ рд╣реИ, рд▓реЗрдХрд┐рди рджреВрд╕рд░реА рддрд░рдл рдпрд╣ рд╕рд┐рджреНрдзрд╛рдВрдд рдХрд╛ рдПрдХ рдЫреЛрдЯрд╛ рд▓реЗрдХрд┐рди рдЕрджреНрднреБрдд рдкреНрд░рджрд░реНрд╢рди рд╣реИред рдРрд╕реЗ рдореИрдХреНрд░реЛ рд╡рд┐рд╕реНрддрд╛рд░ рдХреЗ рд▓рд┐рдП рдЦреБрд▓реЗ рд╣реЛ рдЬрд╛рддреЗ рд╣реИрдВред рд╣рдореЗрдВ рдЕрдкрдиреЗ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЛ рдмрджрд▓рдиреЗ рдпрд╛ рд╡рд┐рд╕реНрддрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдореВрд▓ рдкреНрд░рдХреНрд░рд┐рдпрд╛рддреНрдордХ рдореИрдХреНрд░реЛ рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред рдФрд░ рдЕрдЧрд░ рдЖрдк WASM рдХреЗ рд▓рд┐рдП рдореЙрдбреНрдпреВрд▓ рдХреА рд░рдЬрд┐рд╕реНрдЯреНрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ , рддреЛ рдЖрдк рдХрд╛рд░реНрдЧреЛ рдХреНрд░реЗрдЯ рдЬреИрд╕реЗ рдореЙрдбреНрдпреВрд▓ рд╡рд┐рддрд░рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред