WASM рдХреЗ рд╕рд╛рде рдкреНрд░рдХреНрд░рд┐рдпрд╛рддреНрдордХ рдореИрдХреНрд░реЛ рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░

рдкреНрд░рдХреНрд░рд┐рдпрд╛рддреНрдордХ рдореИрдХреНрд░реЛрдЬрд╝ рдХреЗ рд╡рд┐рднрд┐рдиреНрди рдкрд╣рд▓реБрдУрдВ рдкрд░ рдЕрдкрдиреЗ рд╢реЛрдз рдХреЛ рдЬрд╛рд░реА рд░рдЦрдиреЗ рдХреЗ рд╣рд┐рд╕реНрд╕реЗ рдХреЗ рд░реВрдк рдореЗрдВ, рдореИрдВ рдЙрдирдХреА рдХреНрд╖рдорддрд╛рдУрдВ рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╕рд╛рдЭрд╛ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВред рдЖрдкрдХреЛ рдпрд╛рдж рджрд┐рд▓рд╛ рджреВрдВ рдХрд┐ рдкреНрд░рдХреНрд░рд┐рдпрд╛рддреНрдордХ рдореИрдХреНрд░реЛрдЬрд╝ рдЖрдкрдХреЛ рднрд╛рд╖рд╛ рдореЗрдВ рдПрдХ рдореЗрдЯрд╛рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рддрддреНрд╡ рдЬреЛрдбрд╝рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ рдФрд░ рдЗрд╕ рддрд░рд╣ рдирд┐рдпрдорд┐рдд рд╕рдВрдЪрд╛рд▓рди, рдЬреИрд╕реЗ рдХрд┐ рдХреНрд░рдорд╛рдВрдХрди рдпрд╛ рдХреНрд╡реЗрд░реА рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХреЛ рд╕рд░рд▓ рдмрдирд╛рддрд╛ рд╣реИред рдЙрдирдХреЗ рдореВрд▓ рдореЗрдВ, рдореИрдХреНрд░реЛрдЬрд╝ рдХрдВрдкрд╛рдЗрд▓рд░ рдкреНрд▓рдЧрдЗрдиреНрд╕ рд╣реИрдВ рдЬреЛ рд░реИрдХ рдХреЗ рдирд┐рд░реНрдорд╛рдг рд╕реЗ рдкрд╣рд▓реЗ рд╕рдВрдХрд▓рд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдЬрд┐рд╕рдореЗрдВ рдЙрдирдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдРрд╕реЗ рдореИрдХреНрд░реЛ рдореЗрдВ рдХреБрдЫ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдХрдорд┐рдпрд╛рдВ рд╣реИрдВред


  • рдЖрдИрдбреАрдИ рдореЗрдВ рдРрд╕реЗ рдореИрдХреНрд░реЛрдЬрд╝ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдиреЗ рдореЗрдВ рдХрдард┐рдирд╛рдИред рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдЖрдкрдХреЛ рдХрд┐рд╕реА рддрд░рд╣ рдЗрди рд╕рднреА рдореИрдХреНрд░реЛ рдХреЛ рд╕рдВрдХрд▓рд┐рдд рдХрд░рдиреЗ, рд▓реЛрдб рдХрд░рдиреЗ рдФрд░ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЛрдб рдПрдирд╛рд▓рд╛рдЗрдЬрд╝рд░ рдХреЛ рдкрдврд╝рд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рд╕рднреА рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХреЛ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦрддреЗ рд╣реБрдПред рдпрд╣ рдмрд╣реБрдд рд╣реА рдЧреИрд░-рддреБрдЪреНрдЫ рдХрд╛рд░реНрдп рд╣реИред
  • рдЪреВрдВрдХрд┐ рдореИрдХреНрд░реЛрдЬрд╝ рдЖрддреНрдордирд┐рд░реНрднрд░ рд╣реИрдВ рдФрд░ рдПрдХ-рджреВрд╕рд░реЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреБрдЫ рдирд╣реАрдВ рдЬрд╛рдирддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рдореИрдХреНрд░реЛрдЬрд╝ рдХреА рд░рдЪрдирд╛ рдХрд░рдиреЗ рдХрд╛ рдХреЛрдИ рддрд░реАрдХрд╛ рдирд╣реАрдВ рд╣реИ, рдЬреЛ рдХрднреА-рдХрднреА рдЙрдкрдпреЛрдЧреА рд╣реЛ рд╕рдХрддрд╛ рд╣реИред

рдкрд╣рд▓реА рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, 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());
    //  4  -     ,      
    // .
    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;
    //  ,     ""   `to_host_ptr`  
    //          
    //    .
    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");

    //     ,   .
    // `fn(item: TokenStream) -> TokenStream`
    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> {
        //    WASM ,    .
        let store = Store::default();
        let module = Module::from_file(&store, file)?;
        Ok(Self { module })
    }

    //     `fun`   ,   
    //     TokenStream  .
    pub fn proc_macro_derive(
        &self,
        fun: &str,
        item: TokenStream,
    ) -> anyhow::Result<TokenStream> {
        //    ,   TokenStream  ,
        //      .
        let item = item.to_string();

        //    ,     .
        let instance = Instance::new(&self.module, &[])?;
        //      ,     
        //   `implement_codec`.
        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,>()?;

        //      WASM   
        // ,      .
        let item_buf = WasmBuf::from_host_buf(&instance, item);
        //            
        let (item_ptr, item_len) = item_buf.raw_parts();
        //          
        //      TokenStream. 
        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   .
        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> {
    //    :     `toy_alloc`
    //    .
    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
    }

    //       ,    
    // .            
    //         .
    //      `toy_alloc`  ,    4
    //     .
    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,
        }
    }

    //         .
    //     ,       4 .

    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.");

    //        codecs,   
    //    . 
    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)]
//   ,  WASM      .
#[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 рдХреЗ рд▓рд┐рдП рдореЙрдбреНрдпреВрд▓ рдХреА рд░рдЬрд┐рд╕реНрдЯреНрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ , рддреЛ рдЖрдк рдХрд╛рд░реНрдЧреЛ рдХреНрд░реЗрдЯ рдЬреИрд╕реЗ рдореЙрдбреНрдпреВрд▓ рд╡рд┐рддрд░рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред


All Articles