watt-non-static-runtime 0.4.0

Runtime for executing Rust procedural macros compiled as WebAssembly.
Documentation
#![allow(clippy::identity_op)]

use crate::data::Data;
use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
use std::char;
use std::str::{self, FromStr};

pub fn decode(mut bytes: &[u8], data: &Data) -> TokenStream {
    let ret = TokenStream::decode(&mut bytes, data);
    assert!(bytes.is_empty());
    ret
}

trait Decode {
    fn decode(bytes: &mut &[u8], data: &Data) -> Self;
}

fn byte(data: &mut &[u8]) -> u8 {
    let ret = data[0];
    *data = &data[1..];
    ret
}

fn str<'a>(bytes: &mut &'a [u8], data: &Data) -> &'a str {
    let len = u32::decode(bytes, data) as usize;
    let ret = str::from_utf8(&bytes[..len]).unwrap();
    *bytes = &bytes[len..];
    ret
}

impl Decode for TokenStream {
    fn decode(bytes: &mut &[u8], data: &Data) -> Self {
        let mut tts = Vec::new();
        loop {
            match byte(bytes) {
                0 => break,
                1 => tts.push(TokenTree::Group(Group::decode(bytes, data))),
                2 => tts.push(TokenTree::Ident(Ident::decode(bytes, data))),
                3 => tts.push(TokenTree::Punct(Punct::decode(bytes, data))),
                _ => tts.push(TokenTree::Literal(Literal::decode(bytes, data))),
            }
        }
        tts.into_iter().collect()
    }
}

impl Decode for Group {
    fn decode(bytes: &mut &[u8], data: &Data) -> Self {
        let delimiter = Delimiter::decode(bytes, data);
        let span = Span::decode(bytes, data);
        let stream = TokenStream::decode(bytes, data);
        let mut ret = Group::new(delimiter, stream);
        ret.set_span(span);
        ret
    }
}

impl Decode for Delimiter {
    fn decode(bytes: &mut &[u8], _data: &Data) -> Self {
        match byte(bytes) {
            0 => Delimiter::Parenthesis,
            1 => Delimiter::Brace,
            2 => Delimiter::Bracket,
            _ => Delimiter::None,
        }
    }
}

impl Decode for Span {
    fn decode(bytes: &mut &[u8], data: &Data) -> Self {
        let idx = u32::decode(bytes, data);
        if idx == u32::max_value() {
            Span::call_site()
        } else {
            data.span[idx]
        }
    }
}

impl Decode for u32 {
    fn decode(bytes: &mut &[u8], _data: &Data) -> Self {
        let ret = ((bytes[0] as u32) << 0)
            | ((bytes[1] as u32) << 8)
            | ((bytes[2] as u32) << 16)
            | ((bytes[3] as u32) << 24);
        *bytes = &bytes[4..];
        ret
    }
}

impl Decode for Ident {
    fn decode(bytes: &mut &[u8], data: &Data) -> Self {
        let span = Span::decode(bytes, data);
        let name = str(bytes, data);
        if name.starts_with("r#") {
            match name.parse::<TokenStream>().unwrap().into_iter().next() {
                Some(TokenTree::Ident(ident)) => ident,
                _ => unreachable!(),
            }
        } else {
            Ident::new(name, span)
        }
    }
}

impl Decode for Punct {
    fn decode(bytes: &mut &[u8], data: &Data) -> Self {
        let mut p = Punct::new(
            char::from_u32(u32::decode(bytes, data)).unwrap(),
            Spacing::decode(bytes, data),
        );
        p.set_span(Span::decode(bytes, data));
        p
    }
}

impl Decode for Spacing {
    fn decode(bytes: &mut &[u8], _data: &Data) -> Self {
        match byte(bytes) {
            0 => Spacing::Alone,
            _ => Spacing::Joint,
        }
    }
}

impl Decode for Literal {
    fn decode(bytes: &mut &[u8], data: &Data) -> Self {
        let span = Span::decode(bytes, data);
        if byte(bytes) == 0 {
            let text = str(bytes, data);
            let token = TokenStream::from_str(text)
                .unwrap()
                .into_iter()
                .next()
                .unwrap();
            let mut literal = match token {
                TokenTree::Literal(l) => l,
                _ => unreachable!(),
            };
            literal.set_span(span);
            literal
        } else {
            let mut literal = data.literal[u32::decode(bytes, data)].clone();
            literal.set_span(span);
            literal
        }
    }
}