i have a question on rust macros... i created a custom trait, and i made it derivable...
but now if i try to derive the trait inside a macro it doesn't work (but if i write it manually it does work)
here is the code:
// this is my macro
#[macro_export]
macro_rules! compact {
( $x:ident, $y:ident ) => {
#[derive(Vhdlizable,Debug)]
struct Compact<T,E>{
$x: T,
$y: E
}
};
}
#[test]
fn test_compact_macro(){
let a = 11_i32;
let b = 0_u8;
//this dos't work
//compact!(a,b);
//this works
#[derive(Vhdlizable,Debug)]
struct Compact<T, E,> {
a: T,
b: E,
}
}
the error i get is the following:
error[E0424]: expected value, found module `self`
--> src\tests.rs:103:14
|
90 | #[derive(Vhdlizable,Debug)]
| ---------- this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters
...
103 | compact!(a,b);
| ^ `self` value is a keyword only available in methods with a `self` parameter
i have no idea what could cause this...
it should be noted that if i only derive the Debug trait it works
here is the code to make the trait Derivable:
use proc_macro2::TokenStream;
use quote::{quote, quote_spanned};
use syn::spanned::Spanned;
use syn::{
parse_macro_input, parse_quote, Data, DeriveInput, Fields, GenericParam, Generics,
};
#[test]
fn test(){
}
#[proc_macro_derive(Vhdlizable)]
pub fn derive_vhdliizable(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
// Parse the input tokens into a syntax tree.
let input = parse_macro_input!(input as DeriveInput);
// Used in the quasi-quotation below as `#name`.
let name = input.ident;
// Add a bound `T: HeapSize` to every type parameter T.
let generics = add_trait_bounds(input.generics);
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let necessary_bits = sum_necessary_bits(&input.data);
let bit_rapresentation = concat_bit_representation(&input.data);
let declaration_code = generate_delcaration_code(&input.data);
let construction_code = generate_construction_code(&input.data);
let deconstruction_code = generate_deconstruction_code(&input.data);
let recreate_from_bits_code = generate_recursive_reconstruction(&input.data);
let expanded = quote! {
// The generated impl.
impl #impl_generics Vhdlizable for #name #ty_generics #where_clause {
fn get_necessary_bits() -> usize{
#necessary_bits
}
fn get_bit_representation(&self) -> Vec<bool>{
#bit_rapresentation
}
fn construct_from_bits(data: &[bool]) -> Result<Self,std::io::Error> where Self: Sized{
if data.len() != Self::get_necessary_bits(){
return Err(std::io::Error::new(std::io::ErrorKind::Other, "Length of input incompatible with length of output"));
};
#recreate_from_bits_code
}
fn get_vhd_construction_code(variable_name: &str ,start_index: usize) -> String{
#construction_code
}
fn get_vhd_declaration_code(variable_name: &str ) -> String{
#declaration_code
}
fn get_vhd_deconstruction_code(variable_name: &str ,start_index: usize) -> String{
#deconstruction_code
}
}
};
// Hand the output tokens back to the compiler.
proc_macro::TokenStream::from(expanded)
}
// Add a bound `T: Vhdlizable` to every type parameter T.
fn add_trait_bounds(mut generics: Generics) -> Generics {
for param in &mut generics.params {
if let GenericParam::Type(ref mut type_param) = *param {
type_param.bounds.push(parse_quote!(Vhdlizable));
}
}
generics
}
// Generate an expression to sum up the heap size of each field.
fn sum_necessary_bits(data: &Data) -> TokenStream {
match *data {
Data::Struct(ref data) => {
match data.fields {
Fields::Named(ref fields) => {
let recurse = fields.named.iter().map(|f| {
let type_ = &f.ty;
quote_spanned! {f.span()=>
#type_::get_necessary_bits()
}
});
quote! {
0 #(+ #recurse)*
}
}
Fields::Unnamed(_) => {
unimplemented!("Impossible to derive this trait on unnamed Type")
}
Fields::Unit => {
unimplemented!("Impossible to derive this trait on unit Type")
}
}
}
Data::Enum(_) | Data::Union(_) => unimplemented!(),
}
}
fn concat_bit_representation(data: &Data) -> TokenStream {
match *data {
Data::Struct(ref data) => {
match data.fields {
Fields::Named(ref fields) => {
let recurse: Vec<_> = fields.named.iter().map(|f| {
let name = &f.ident;
quote_spanned! {f.span()=>
self.#name.get_bit_representation()
}
}).collect();
quote! {
let mut v = vec![false;0];
#(v.extend(#recurse);)*
v
}
}
Fields::Unnamed(_) => {
unimplemented!("Impossible to derive this trait on unnamed Type")
}
Fields::Unit => {
unimplemented!("Impossible to derive this trait on unit Type")
}
}
}
Data::Enum(_) | Data::Union(_) => unimplemented!(),
}
}
fn generate_delcaration_code(data: &Data) -> TokenStream {
match *data {
Data::Struct(ref data) => {
match data.fields {
Fields::Named(ref fields) => {
let recurse: Vec<_> = fields.named.iter().map(|f| {
let name = &f.ident;
let type_ = &f.ty;
quote_spanned! {f.span()=>
//self.#name.get_delcaration_code("name")
#type_::get_vhd_declaration_code(
&format!("{}_{}",variable_name,stringify!(#name))[..]
)
}
}).collect();
quote! {
let mut s = String::new();
#(s.push_str(&(#recurse)[..]);)*
s
}
}
Fields::Unnamed(_) => {
unimplemented!("Impossible to derive this trait on unnamed Type")
}
Fields::Unit => {
unimplemented!("Impossible to derive this trait on unit Type")
}
}
}
Data::Enum(_) | Data::Union(_) => unimplemented!(),
}
}
fn generate_construction_code(data: &Data) -> TokenStream {
match *data {
Data::Struct(ref data) => {
match data.fields {
Fields::Named(ref fields) => {
let recurse: Vec<_> = fields.named.iter().map(|f| {
let name = &f.ident;
let type_ = &f.ty;
quote_spanned! {f.span()=>
#type_::get_vhd_construction_code(
&format!("{}_{}",variable_name,stringify!(#name))[..],
start_from
)
}
}).collect();
let sizes: Vec<_> = fields.named.iter().map(|f| {
let type_ = &f.ty;
quote_spanned! {f.span()=>
#type_::get_necessary_bits()
}
}).collect();
quote! {
let mut start_from = start_index;
let mut s = String::new();
#(
s.push_str(&(#recurse)[..]);
start_from += #sizes;
)*
s
}
}
Fields::Unnamed(_) => {
unimplemented!("Impossible to derive this trait on unnamed Type")
}
Fields::Unit => {
unimplemented!("Impossible to derive this trait on unit Type")
}
}
}
Data::Enum(_) | Data::Union(_) => unimplemented!(),
}
}
fn generate_deconstruction_code(data: &Data) -> TokenStream {
match *data {
Data::Struct(ref data) => {
match data.fields {
Fields::Named(ref fields) => {
let recurse: Vec<_> = fields.named.iter().map(|f| {
let name = &f.ident;
let type_ = &f.ty;
quote_spanned! {f.span()=>
#type_::get_vhd_deconstruction_code(
&format!("{}_{}",variable_name,stringify!(#name))[..],
start_from
)
}
}).collect();
let sizes: Vec<_> = fields.named.iter().map(|f| {
let type_ = &f.ty;
quote_spanned! {f.span()=>
#type_::get_necessary_bits()
}
}).collect();
quote! {
let mut start_from = start_index;
let mut s = String::new();
#(
s.push_str(&(#recurse)[..]);
start_from += #sizes;
)*
s
}
}
Fields::Unnamed(_) => {
unimplemented!("Impossible to derive this trait on unnamed Type")
}
Fields::Unit => {
unimplemented!("Impossible to derive this trait on unit Type")
}
}
}
Data::Enum(_) | Data::Union(_) => unimplemented!(),
}
}
fn generate_recursive_reconstruction(data: &Data) -> TokenStream {
match *data {
Data::Struct(ref data) => {
match data.fields {
Fields::Named(ref fields) => {
let recurse: Vec<_> = fields.named.iter().map(|f| {
let name = &f.ident;
let type_ = &f.ty;
quote_spanned! {f.span()=>
let n = #type_::get_necessary_bits();
let v = &data[counter..(counter+n)];
counter += n;
let #name: #type_ = #type_::construct_from_bits(v)?;
}
}).collect();
let names: Vec<_> = fields.named.iter().map(|f| {
let name = &f.ident;
quote_spanned! {f.span()=>
#name
}
}).collect();
quote! {
let mut counter = 0_usize;
#(
#recurse
)*
Ok(Self{
#(
#names,
)*
})
}
}
Fields::Unnamed(_) => {
unimplemented!("Impossible to derive this trait on unnamed Type")
}
Fields::Unit => {
unimplemented!("Impossible to derive this trait on unit Type")
}
}
}
Data::Enum(_) | Data::Union(_) => unimplemented!(),
}
}
i switch to nightly rust to expand the code... and it works now...
if you are still interested in or, here is the expanded code:
#[allow(unused_imports)]
#[allow(dead_code)]
mod tests {
use std::fmt::Debug;
#[allow(unused_imports)]
use crate::communicate_to_vhdl::{Communicator, Vhdlizable};
fn test_compact_macro() {
let a = 11_i32;
let b = 0_u8;
struct Compact<T, E> {
a: T,
b: E,
}
impl<T: Vhdlizable, E: Vhdlizable> Vhdlizable for Compact<T, E> {
fn get_necessary_bits() -> usize {
0 + T::get_necessary_bits() + E::get_necessary_bits()
}
fn get_bit_representation(&self) -> Vec<bool> {
let mut v = ::alloc::vec::from_elem(false, 0);
v.extend(self.a.get_bit_representation());
v.extend(self.b.get_bit_representation());
v
}
fn construct_from_bits(data: &[bool]) -> Result<Self, std::io::Error>
where
Self: Sized,
{
if data.len() != Self::get_necessary_bits() {
return Err(
std::io::Error::new(
std::io::ErrorKind::Other,
"Length of input incompatible with length of output",
),
);
}
let mut counter = 0_usize;
let n = T::get_necessary_bits();
let v = &data[counter..(counter + n)];
counter += n;
let a: T = T::construct_from_bits(v)?;
let n = E::get_necessary_bits();
let v = &data[counter..(counter + n)];
counter += n;
let b: E = E::construct_from_bits(v)?;
Ok(Self { a, b })
}
fn get_vhd_construction_code(
variable_name: &str,
start_index: usize,
) -> String {
let mut start_from = start_index;
let mut s = String::new();
s.push_str(
&(T::get_vhd_construction_code(
&{
let res = ::alloc::fmt::format(
format_args!("{0}_{1}", variable_name, "a"),
);
res
}[..],
start_from,
))[..],
);
start_from += T::get_necessary_bits();
s.push_str(
&(E::get_vhd_construction_code(
&{
let res = ::alloc::fmt::format(
format_args!("{0}_{1}", variable_name, "b"),
);
res
}[..],
start_from,
))[..],
);
start_from += E::get_necessary_bits();
s
}
fn get_vhd_declaration_code(variable_name: &str) -> String {
let mut s = String::new();
s.push_str(
&(T::get_vhd_declaration_code(
&{
let res = ::alloc::fmt::format(
format_args!("{0}_{1}", variable_name, "a"),
);
res
}[..],
))[..],
);
s.push_str(
&(E::get_vhd_declaration_code(
&{
let res = ::alloc::fmt::format(
format_args!("{0}_{1}", variable_name, "b"),
);
res
}[..],
))[..],
);
s
}
fn get_vhd_deconstruction_code(
variable_name: &str,
start_index: usize,
) -> String {
let mut start_from = start_index;
let mut s = String::new();
s.push_str(
&(T::get_vhd_deconstruction_code(
&{
let res = ::alloc::fmt::format(
format_args!("{0}_{1}", variable_name, "a"),
);
res
}[..],
start_from,
))[..],
"Compact",
"a",
&self.a,
"b",
&&self.b,
)
}
}
}
}
Related
I'm new to Rust and have implemented a network receiver thread where in I'm testing my implementation by sending data to the same socket address the receiver socket is bound to(making use of dynamic binding by binding the socket to port 0). But I'm getting thread 'google' panicked at 'Didn't receive data: Os { code: 10054, kind: ConnectionReset, message: "An existing connection was forcibly closed by the remote host." }', src\ethernet_interface.rs:62:42. This is my code
src/main.rs
mod ethernet_interface;
mod WWW_sim_interface;
use crate::WWW_sim_interface::WWWSimInterface;
use std::{thread, time};
fn main() {
let www_sim_interface = WWWSimInterface::new(String::from("google"));
let mut www_sim_interface_runnable = www_sim_interface.start();
let two_seconds = time::Duration::from_secs(2);
thread::sleep(two_seconds);
www_sim_interface_runnable.terminate_WWW_sim();
www_sim_interface_runnable.join_handle.join();
}
src/WWW_sim_interface.rs
use std::net::{SocketAddr, IpAddr, Ipv4Addr};
use std::thread;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
use std::mem;
use crate::ethernet_interface::EthernetInterface;
pub struct WWWSimInterface {
target_ID: String,
terminate_flag: AtomicBool,
eth_interface: Option<EthernetInterface>,
}
pub struct RunningWWWSimInterface {
pub join_handle: thread::JoinHandle<()>,
WWW_sim_interface: Arc<WWWSimInterface>,
}
impl WWWSimInterface {
pub fn new(target_ID: String) -> WWWSimInterface {
let mut WWW_sim_interface = WWWSimInterface {
target_ID: target_ID,
terminate_flag: AtomicBool::new(false),
eth_interface: Some(EthernetInterface::new()),
};
WWW_sim_interface.eth_interface.as_mut().expect("Error").setup_receiver(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 0));
WWW_sim_interface
}
pub fn start(self) -> RunningWWWSimInterface {
let WWW_sim_interface = Arc::new(self);
let join_handle = {
let WWW_sim_interface = WWW_sim_interface.clone();
thread::Builder::new().name(WWW_sim_interface.target_ID.clone()).spawn(move || WWW_sim_interface.run()).ok().unwrap()
};
RunningWWWSimInterface {
join_handle,
WWW_sim_interface,
}
}
pub fn run(&self) {
let mut buff: [u8; 2048] = [0; 2048];
let mut msg_ID: u16;
println!("started receiver thread");
while !self.terminate_flag.load(Ordering::Relaxed) {
let data_len = self.eth_interface.as_ref().expect("Error").recv_data(&mut buff);
if data_len < 2 {
continue;
}
let vec_buff = buff[..data_len].to_vec();
let (int_bytes, rest) = buff.split_at(mem::size_of::<u16>());
msg_ID = u16::from_be_bytes(int_bytes.try_into().unwrap());
if msg_ID == 1234 {
break;
}
}
}
}
impl RunningWWW_simInterface {
pub fn terminate_WWWSim(&mut self) {
self.WWW_sim_interface.terminate_flag.store(true, Ordering::Relaxed);
let msg_ID: u16 = 1234;
// self.WWW_sim_interface.eth_interface.as_ref().expect("Error").send_data(&msg_ID.to_be_bytes());
self.WWW_sim_interface.eth_interface.as_ref().expect("Error").send_self(&msg_ID.to_be_bytes());
}
}
src/ethernet_interface.rs
use std::net::{UdpSocket, SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr};
use std::net::IpAddr::V4;
use std::net::IpAddr::V6;
pub struct EthernetInterface {
socket: Option<UdpSocket>,
recv_IP_sock_addr: Option<SocketAddr>,
send_IP_sock_addr: Option<SocketAddr>,
}
impl EthernetInterface {
pub fn new() -> EthernetInterface {
EthernetInterface {
socket: None,
recv_IP_sock_addr: None,
send_IP_sock_addr: None,
}
}
pub fn setup_receiver(&mut self, mut recv_IP_sock_addr: SocketAddr) {
let ip_addr = recv_IP_sock_addr.ip();
let first_octect: u8 = match ip_addr {
V4(ip4_addr) => ip4_addr.octets().to_vec()[0],
V6(ip6_addr) => ip6_addr.octets().to_vec()[0]
};
if first_octect > 223 && first_octect < 240 {
match ip_addr {
V4(ip4_addr) => recv_IP_sock_addr.set_ip(IpAddr::V4(Ipv4Addr::UNSPECIFIED)),
V6(ip6_addr) => recv_IP_sock_addr.set_ip(IpAddr::V6(Ipv6Addr::UNSPECIFIED))
};
}
self.recv_IP_sock_addr = Some(recv_IP_sock_addr);
self.socket = Some(UdpSocket::bind(self.recv_IP_sock_addr.unwrap()).unwrap());
if first_octect > 223 && first_octect < 240 {
let ip_addr = self.recv_IP_sock_addr.unwrap().ip();
match ip_addr {
V4(ip4_addr) => self.socket.as_ref().unwrap().join_multicast_v4(&ip4_addr, &Ipv4Addr::UNSPECIFIED).ok(),
V6(ip6_addr) => self.socket.as_ref().unwrap().join_multicast_v6(&ip6_addr, 0).ok()
};
}
}
pub fn setup_sender(&mut self, send_IP_sock_addr: SocketAddr) {
let ip_addr = send_IP_sock_addr.ip();
let first_octect = match ip_addr {
V4(ip4_addr) => ip4_addr.octets().to_vec()[0],
V6(ip6_addr) => ip6_addr.octets().to_vec()[0]
};
self.send_IP_sock_addr = Some(send_IP_sock_addr);
if first_octect > 223 && first_octect < 240 {
self.socket.as_ref().unwrap().set_multicast_loop_v4(false).expect("set_multicast_loop_v4 call failed");
self.socket.as_ref().unwrap().set_multicast_ttl_v4(8).expect("set_multicast_ttl_v4 call failed");
}
}
pub fn recv_data(&self, buff: &mut [u8]) -> usize {
let (number_of_bytes, src_addr) = self.socket.as_ref().unwrap().recv_from(buff)
.expect("Didn't receive data");
println!("recvd data");
number_of_bytes
}
pub fn send_data(&self, buff: &[u8]) {
self.socket.as_ref().unwrap().send_to(buff, self.send_IP_sock_addr.unwrap()).expect("couldn't send data");
}
pub fn get_host_bound_port(&self) -> u16 {
self.socket.as_ref().unwrap().local_addr().unwrap().port()
}
pub fn get_src_addr(&mut self) {
let mut buff: [u8; 2048] = [0; 2048];
let (_, src_addr) = self.socket.as_ref().unwrap().recv_from(&mut buff)
.expect("Didn't receive data");
self.send_IP_sock_addr = Some(src_addr);
}
pub fn send_self(&self, buff: &[u8]) {
self.socket.as_ref().unwrap().send_to(buff, self.recv_IP_sock_addr.unwrap()).expect("couldn't end self data");
println!("sent data");
}
}
I have a proc_macro that produces a telemetry function to parse a structs member variables and it works great for non nested structs. I have found that I need to recursively call my handle_named_field function on any syn::Field that is a struct. The problem is that I cannot see a way to determine if a field is a struct or not, if I had a syn::Data variable it is trivial, like in my handle_data.
How can I check inside of handle_named_fields(fields: &syn::FieldsNamed) if a field is a struct or not?
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, parse_quote, DeriveInput};
#[proc_macro_derive(Telemetry)]
pub fn derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let output = parse_derive_input(&input);
match output {
syn::Result::Ok(tt) => tt,
syn::Result::Err(err) => err.to_compile_error(),
}
.into()
}
fn parse_derive_input(input: &syn::DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
let struct_ident = &input.ident;
let struct_data = parse_data(&input.data)?;
let struct_fields = &struct_data.fields;
let _struct_ident_str = format!("{}", struct_ident);
let tele_body = match struct_fields {
syn::Fields::Named(fields_named) => handle_named_fields(fields_named)?,
syn::Fields::Unnamed(fields_unnamed) => {
let field_indexes = (0..fields_unnamed.unnamed.len()).map(syn::Index::from);
let field_indexes_str = (0..fields_unnamed.unnamed.len()).map(|idx| format!("{}", idx));
quote!(#( .field(#field_indexes_str, &self.#field_indexes) )*)
}
syn::Fields::Unit => quote!(),
};
let telemetry_declaration = quote!(
trait Telemetry {
fn telemetry(self, header_stream: Arc<Mutex::<Box <std::io::Write + std::marker::Send + Sync>>>, data_stream: Arc<Mutex::<Box <std::io::Write + std::marker::Send + Sync>>>);
}
);
syn::Result::Ok(
quote!(
use std::thread;
use std::collections::VecDeque;
#[derive(Serialize, Deserialize, Default, Debug)]
pub struct VariableDescription {
pub var_name_length: usize,
pub var_name: String,
pub var_type_length: usize,
pub var_type: String,
pub var_size: usize,
}
#[derive(Serialize, Deserialize, Default, Debug)]
pub struct TelemetryHeader {
pub variable_descriptions: VecDeque::<VariableDescription>,
}
#telemetry_declaration
impl Telemetry for #struct_ident {
fn telemetry(self, header_stream: Arc<Mutex::<Box <std::io::Write + std::marker::Send + Sync>>>, data_stream: Arc<Mutex::<Box <std::io::Write + std::marker::Send + Sync>>>) {
thread::spawn(move || {
#tele_body;
});
}
}
)
)
}
fn handle_named_fields(fields: &syn::FieldsNamed) -> syn::Result<proc_macro2::TokenStream> {
let idents = fields.named.iter().map(|f| &f.ident);
let types = fields.named.iter().map(|f| &f.ty);
let num_entities = fields.named.len();
let test = quote! (
let mut tele_header = TelemetryHeader {variable_descriptions: VecDeque::with_capacity(#num_entities)};
#(
if()
tele_header.variable_descriptions.push_back( VariableDescription {
var_name_length: stringify!(#idents).len(),
var_name: stringify!(#idents).to_string(),
var_type_length: stringify!(#types).len(),
var_type: stringify!(#types).to_string(),
var_size: std::mem::size_of_val(&self.#idents),
});
)*
header_stream.lock().unwrap().write(&bincode::serialize(&tele_header).unwrap()).unwrap();
data_stream.lock().unwrap().write(&bincode::serialize(&self).unwrap()).unwrap();
);
syn::Result::Ok(test)
}
fn parse_named_field(field: &syn::Field) -> proc_macro2::TokenStream {
let ident = field.ident.as_ref().unwrap();
let ident_str = format!("{}", ident);
let ident_type = &field.ty;
if field.attrs.is_empty() {
quote!(
if true {
println!("TRUE");
}
println!("Var Name Length: {}", stringify!(#ident_str).len());
println!("Var Name: {}", #ident_str);
println!("Var Type Length: {}", stringify!(#ident_type).len());
println!("Var Type: {}", stringify!(#ident_type));
println!("Var Val: {}", &self.#ident);
)
}
else {
quote!()
}
}
fn parse_data(data: &syn::Data) -> syn::Result<&syn::DataStruct> {
match data {
syn::Data::Struct(data_struct) => syn::Result::Ok(data_struct),
syn::Data::Enum(syn::DataEnum { enum_token, .. }) => syn::Result::Err(
syn::Error::new_spanned(enum_token, "CustomDebug is not implemented for enums"),
),
syn::Data::Union(syn::DataUnion { union_token, .. }) => syn::Result::Err(
syn::Error::new_spanned(union_token, "CustomDebug is not implemented for unions"),
),
}
}
I've implemented the following proc_macro that takes
builtin_method!(hello_world(a, b, c) {
println!("{} {} {}", a, b, c);
}
and should generate
pub fn hello_world(args: Vec<String>) {
let a = args.get(0).unwrap();
let b = args.get(1).unwrap();
let c = args.get(2).unwrap();
println!("{} {} {}", a, b, c);
}
Here's my current code.
use proc_macro::TokenStream;
use quote::quote;
use syn;
struct BuiltinDef {
function: syn::Ident,
arguments: Vec<syn::Ident>,
body: syn::Block,
}
impl syn::parse::Parse for BuiltinDef {
fn parse(stream: syn::parse::ParseStream) -> syn::Result<Self> {
let function: syn::Ident = stream.parse()?;
let content;
let _: syn::token::Paren = syn::parenthesized!(content in stream);
let arguments: syn::punctuated::Punctuated<syn::Ident, syn::Token![,]> =
content.parse_terminated(syn::Ident::parse)?;
let body: syn::Block = stream.parse()?;
Ok(BuiltinDef {
function,
arguments: arguments.into_iter().collect(),
body,
})
}
}
#[proc_macro]
pub fn builtin_method(input: TokenStream) -> TokenStream {
let def = syn::parse_macro_input!(input as BuiltinDef);
let function = def.function;
let arguments = def.arguments;
let body = def.body;
let gen = quote! {
pub fn #function(args: Vec<String>) {
let mut _i = 0;
#(
let mut #arguments = args.get(_i).unwrap().clone();
_i += 1;
)*
#body
}
};
TokenStream::from(gen)
}
Inside the variable interpolation, I need some kind of enumerating variable counting up.
According to the docs there is not such way.
How can I implement this better instead of counting up _i?
let mut _i = 0;
#(
let mut #arguments = args.get(_i).unwrap().clone();
_i += 1;
)*
Use standard Iterator::enumerate():
let arguments = arguments.into_iter().enumerate().map(|(index, arg)| quote! {
let mut #arg = args.get(#index).unwrap().clone();
});
let gen = quote! {
pub fn #function(args: Vec<String>) {
let mut _i = 0;
#(#arguments)*
#body
}
};
Ok after following https://stackoverflow.com/a/70939071/694705 I was able to implement it this way by collecting the arguments back into a Vec<proc_macro2::TokenStream>.
Here's my solution:
let arguments: Vec<proc_macro2::TokenStream> =
arguments
.into_iter()
.enumerate()
.map(|(idx, arg)| {
quote! {
let mut #arg = args.get(#idx).unwrap().clone();
}
})
.collect();
let gen = quote! {
pub fn #function(args: Vec<String>) {
#(#arguments)*
#body
}
};
I am writing a macro for a struct and implementing a method based on the field type. e.g. u8, Array or str.
let us say I have this enum represented as u32.
#[repr(u32)]
#[derive(Debug, Clone, Copy)]
pub enum ServerGreetingMode {
Unavailable = 0,
Unauthenticated = 1,
Authenticated = 2,
Encrypted = 4,
}
And I am applying a macro ToBytes on a struct field
#[repr(packed)]
#[derive(ToBytes, Debug, Clone, Copy)]
pub struct ServerGreetingFrame {
pub unused: [u8; 12],
pub mode: ServerGreetingMode,
pub challenge: [u8; 16],
pub salt: [u8; 16],
pub count: u32,
pub mbz: [u8; 12],
}
I am able to get it to a part where I am getting the type as ServerGreetingMode but I am unable to tell if it is an enum or not.
Here is my current implementation.
#[proc_macro_derive(ToBytes)]
pub fn derive(tokens: TokenStream) -> TokenStream {
let tokens_item = tokens.clone();
let items = syn::parse_macro_input!(tokens_item as syn::Item);
let output = match items {
syn::Item::Struct(item) => {
let name = &item.ident;
let statements = match &item.fields {
syn::Fields::Named(ref fields) => {
// eprint!("{:#?}", field);
let vary_by_type = fields.named.iter().map(|field| {
let field_name = &field.ident;
let field_type = &field.ty;
let statement = match field_type {
syn::Type::Array(syn::TypeArray { elem, .. }) => {
let ty = elem.as_ref();
match ty {
syn::Type::Path(typepath)
if typepath.qself.is_none()
&& typepath.path.leading_colon.is_none()
&& typepath.path.segments.len() == 1 && typepath.path.is_ident("u8") =>
{
quote! {
bytes.extend_from_slice(&self.#field_name);
}
},
_ => todo!(),
}
}
syn::Type::Path(ty) if ty.path.clone().is_ident("u32") => {
quote! {
bytes.extend_from_slice(&(self.#field_name as u32).to_be_bytes().to_vec());
}
},
_ => todo!(),
};
statement
});
vary_by_type
}
_ => todo!(),
};
quote! {
impl #name {
fn to_bytes(&self) -> Vec<u8> {
let mut bytes: Vec<u8> = Vec::new();
#(
#statements
)*
bytes
}
}
}
}
_ => todo!(),
};
output.into()
// let s = syn::parse_macro_input!(tokens_struct as syn::ItemStruct);
// let n = &s.ident;
// let expanded = quote! {
// impl #n {
// fn to_bytes(&self) -> Vec<u8> {
// let mut bytes: Vec<u8> = Vec::new();
// bytes
// }
// }
// };
// expanded.into()
}
Thanks.
How can you call Linux' socketpair() command in rust?
I was not able to find it in the documentation.
This is how it works:
use std::io;
use std::libc;
use std::libc::consts::os::bsd44;
use std::libc::funcs::bsd43;
extern {
fn socketpair(
domain: libc::c_int,
typ: libc::c_int,
protocol: libc::c_int,
sv: *libc::c_int
) -> libc::c_int;
}
struct PairedStream {
socket: i32
}
impl PairedStream {
fn new(fd: i32) -> PairedStream {
PairedStream {socket: fd}
}
fn send(&self, buf: &[u8]) -> Result<(), io::IoError> {
let res = unsafe {
let ptr = buf.as_ptr() as *mut libc::c_void;
let len = buf.len() as u64;
bsd43::send(self.socket, ptr, len, 0) as uint == buf.len()
};
if res {
return Ok(());
}
else {
return Err(io::IoError {
kind: io::OtherIoError,
desc: "TODO: determine error types ;)",
detail: None,
})
}
}
fn read(&self, buf: &mut [u8]) -> Result<uint, io::IoError> {
let len = unsafe {
let ptr = buf.as_ptr() as *mut libc::c_void;
let len = buf.len() as u64;
bsd43::recv(self.socket, ptr, len, 0)
};
if len == -1 {
return Err(io::IoError {
kind: io::OtherIoError,
desc: "TODO: determine error types ;)",
detail: None,
})
}
else {
return Ok(len as uint);
}
}
}
struct SocketPair;
impl SocketPair {
fn new() -> (Result<(PairedStream, PairedStream), io::IoError>) {
let AF_LOCAL = 1;
let sv: [i32, ..2] = [-1, -1];
let _type = bsd44::SOCK_DGRAM;
let res = unsafe {
socketpair(AF_LOCAL, _type, 0, sv.as_ptr()) == 0
};
if res {
let s1 = PairedStream::new(sv[0]);
let s2 = PairedStream::new(sv[1]);
return Ok((s1, s2));
}
else {
return Err(io::IoError {
kind: io::OtherIoError,
desc: "TODO: determine error types ;)",
detail: None,
})
}
}
}
fn main() {
let sockets = SocketPair::new();
match sockets {
Ok((s1, s2)) => {
let mut buf = [9,8,7,6,5,4,3,2,1];
s1.send([1,2,3,4,5,6,7,8,9]);
s2.read(buf);
println!("{} {}", buf[0], buf[8])
}
Err(ioerr) => {}
}
}