#![crate_type = "proc-macro"]
extern crate proc_macro;
mod arg_parser;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::str::FromStr;
use proc_macro::{Span, TokenStream};
use arg_parser::ArgParser;
use proc_macro_error::{abort, proc_macro_error};
#[cfg(feature = "std")]
const OBJECT_PREFIX: &'static str = "std::net";
#[cfg(not(feature = "std"))]
const OBJECT_PREFIX: &'static str = "core::net";
fn generate_ipv4_stream(addr: &Ipv4Addr) -> TokenStream {
let [a, b, c, d] = addr.octets();
format!("{OBJECT_PREFIX}::Ipv4Addr::new({a}, {b}, {c}, {d})")
.parse()
.unwrap()
}
fn generate_ipv4_socket_stream(socket: &SocketAddrV4) -> TokenStream {
let addr = socket.ip();
let port = socket.port();
let ip_stream = generate_ipv4_stream(addr);
format!("{OBJECT_PREFIX}::SocketAddrV4::new({ip_stream},{port})")
.parse()
.unwrap()
}
fn generate_ipv6_stream(addr: &Ipv6Addr) -> TokenStream {
let [a, b, c, d, e, f, g, h] = addr.segments();
format!("{OBJECT_PREFIX}::Ipv6Addr::new({a}, {b}, {c}, {d}, {e}, {f}, {g}, {h})")
.parse()
.unwrap()
}
fn generate_ipv6_socket_stream(socket: &SocketAddrV6) -> TokenStream {
let addr = socket.ip();
let port = socket.port();
let flow_info = socket.flowinfo();
let scope_id = socket.scope_id();
let ip_stream = generate_ipv6_stream(addr);
format!("{OBJECT_PREFIX}::SocketAddrV6::new({ip_stream},{port},{flow_info},{scope_id})")
.parse()
.unwrap()
}
fn generate_ip_stream(addr: &IpAddr) -> TokenStream {
match addr {
IpAddr::V4(ip) => {
let ip_stream = generate_ipv4_stream(ip);
format!("{OBJECT_PREFIX}::IpAddr::V4({ip_stream})")
.parse()
.unwrap()
}
IpAddr::V6(ip) => {
let ip_stream = generate_ipv6_stream(ip);
format!("{OBJECT_PREFIX}::IpAddr::V6({ip_stream})")
.parse()
.unwrap()
}
}
}
fn generate_ip_socket_stream(socket: &SocketAddr) -> TokenStream {
match socket {
SocketAddr::V4(socket) => {
let socket_stream = generate_ipv4_socket_stream(socket);
format!("{OBJECT_PREFIX}::SocketAddr::V4({socket_stream})")
.parse()
.unwrap()
}
SocketAddr::V6(socket) => {
let socket_stream = generate_ipv6_socket_stream(socket);
format!("{OBJECT_PREFIX}::SocketAddr::V6({socket_stream})")
.parse()
.unwrap()
}
}
}
fn report_error<T>(value: Result<T, arg_parser::Error>) -> T {
match value {
Ok(v) => v,
Err(e) => {
abort!(e.span(), "{}", e);
}
}
}
fn report_too_few_arguments_error(given: usize, expected: usize) -> ! {
abort!(
Span::call_site(),
"Too few argument: Given {}, expected {}",
given,
expected
);
}
fn report_too_many_arguments_error(span: Span, given: usize, expected: usize) -> ! {
abort!(
span,
"Too many arguments: Given {}, expected {}",
given,
expected
);
}
#[proc_macro_error]
#[proc_macro]
pub fn ipv4(item: TokenStream) -> TokenStream {
let mut parser = ArgParser::from(item);
let ip = if let Some((v, span)) = report_error(parser.next_string()) {
match Ipv4Addr::from_str(v.as_str()) {
Ok(v) => v,
Err(_) => {
abort!(
span,
"The given address `{}` is not a valid IPv4 address",
v
);
}
}
} else {
report_too_few_arguments_error(0, 1);
};
if let Some(span) = report_error(parser.ignore_next()) {
report_too_many_arguments_error(span, parser.count_arguments(), 1);
}
generate_ipv4_stream(&ip)
}
#[proc_macro_error]
#[proc_macro]
pub fn ipv6(item: TokenStream) -> TokenStream {
let mut parser = ArgParser::from(item);
let ip = if let Some((v, span)) = report_error(parser.next_string()) {
match Ipv6Addr::from_str(v.as_str()) {
Ok(v) => v,
Err(_) => {
abort!(
span,
"The given address `{}` is not a valid IPv6 address",
v
);
}
}
} else {
report_too_few_arguments_error(0, 1);
};
if let Some(span) = report_error(parser.ignore_next()) {
report_too_many_arguments_error(span, parser.count_arguments(), 1);
}
generate_ipv6_stream(&ip)
}
#[proc_macro_error]
#[proc_macro]
pub fn ip(item: TokenStream) -> TokenStream {
let mut parser = ArgParser::from(item);
let ip = if let Some((v, span)) = report_error(parser.next_string()) {
match IpAddr::from_str(v.as_str()) {
Ok(v) => v,
Err(_) => {
abort!(span, "The given address `{}` is not a valid IP address", v);
}
}
} else {
report_too_few_arguments_error(0, 1);
};
if let Some(span) = report_error(parser.ignore_next()) {
report_too_many_arguments_error(span, parser.count_arguments(), 1);
}
generate_ip_stream(&ip)
}
#[proc_macro_error]
#[proc_macro]
pub fn socketv4(item: TokenStream) -> TokenStream {
let mut parser = ArgParser::from(item);
let socket = if let Some((v, span)) = report_error(parser.next_string()) {
match SocketAddrV4::from_str(v.as_str()) {
Ok(v) => v,
Err(_) => {
abort!(
span,
"The given address `{}` is not a valid IPv4 socket address",
v
);
}
}
} else {
report_too_few_arguments_error(0, 1);
};
if let Some(span) = report_error(parser.ignore_next()) {
report_too_many_arguments_error(span, parser.count_arguments(), 1);
}
generate_ipv4_socket_stream(&socket)
}
#[proc_macro_error]
#[proc_macro]
pub fn socketv6(item: TokenStream) -> TokenStream {
let mut parser = ArgParser::from(item);
let mut socket = if let Some((v, span)) = report_error(parser.next_string()) {
match SocketAddrV6::from_str(v.as_str()) {
Ok(v) => v,
Err(_) => {
abort!(
span,
"The given address `{}` is not a valid IPv6 socket address",
v
);
}
}
} else {
report_too_few_arguments_error(0, 1);
};
if let Some((flow_info, _)) = report_error(parser.next_integer()) {
socket.set_flowinfo(flow_info);
}
if let Some((scope_id, _)) = report_error(parser.next_integer()) {
socket.set_scope_id(scope_id)
}
if let Some(span) = report_error(parser.ignore_next()) {
report_too_many_arguments_error(span, parser.count_arguments(), 3);
}
generate_ipv6_socket_stream(&socket)
}
#[proc_macro_error]
#[proc_macro]
pub fn socket(item: TokenStream) -> TokenStream {
let mut parser = ArgParser::from(item);
let socket = if let Some((v, span)) = report_error(parser.next_string()) {
match SocketAddr::from_str(v.as_str()) {
Ok(v) => v,
Err(_) => {
abort!(
span,
"The given address `{}` is not a valid socket address",
v
);
}
}
} else {
report_too_few_arguments_error(0, 1);
};
if let Some(span) = report_error(parser.ignore_next()) {
report_too_many_arguments_error(span, parser.count_arguments(), 1);
}
generate_ip_socket_stream(&socket)
}