Embed variable within macro - rust

I'm working with Rust and Rocket.
At some point I can create a catcher to capture errors with:
#[catch(403)]
pub fn default_catcher() -> String {
return String::from("something interesting");
}
As you can imagine the macro #[catch(403)] is capturing errors 403.
Would it be possible to pass a constant to the macro? Something like:
const STATUS_CUSTOM_AUTHENTICATION_ERROR: u16 = 403;
#[catch(`${STATUS_CUSTOM_AUTHENTICATION_ERROR}`)]
...

Not with the macro.
If you want, you can write the boilerplate manually (please don't). The name of the static is important (it's how Rocket finds it):
// This is your function.
pub fn default_catcher() -> String {
String::from("something interesting")
}
pub fn rocket_catch_fn_default_catcher(req: &rocket::Request) -> rocket::Result<'_> {
let response = rocket::Responder::respond_to(default_catcher(), req)?;
rocket::Response::build()
.status(rocket::http::Status::new(
STATUS_CUSTOM_AUTHENTICATION_ERROR,
"some reason (e.g. `Forbidden` for 403)",
))
.merge(response)
.ok()
}
#[allow(non_upper_case_globals)]
pub static static_rocket_catch_info_for_default_catcher: rocket::StaticCatchInfo =
rocket::StaticCatchInfo {
code: 403u16,
handler: rocket_catch_fn_default_catcher,
};
Keep in mind that these are implementation details and can change at any moment.

Related

Is there a way to simplify the access to an inner functionality of web_sys?

After reading the Rust book, I've decided to give it a try with Web Assembly. I'm creating a simple tracker script to practice and learn more about it. There are a couple of methods that need to access the window, navigator or cookie API. Every time I have to access any of those there are a lot of boiler plate code involved:
pub fn start() {
let window = web_sys::window().unwrap();
let document = window.document().unwrap();
let html = document.dyn_into::<web_sys::HtmlDocument>().unwrap();
let cookie = html_document.cookie().unwrap();
}
That's unpractical and bothers me. Is there a smart way to solve this? I've in fact tried to use lazy_static to have all of this in a global.rs file:
#[macro_use]
extern crate lazy_static;
use web_sys::*;
lazy_static! {
static ref WINDOW: window = {
web_sys::window().unwrap()
};
}
But the compile fails with: *mut u8 cannot be shared between threads safely`.
You could use the ? operator instead of unwrapping.
Instead of writing
pub fn start() {
let window = web_sys::window().unwrap();
let document = window.document().unwrap();
let html = document.dyn_into::<web_sys::HtmlDocument>().unwrap();
let cookie = html_document.cookie().unwrap();
}
You can write
pub fn start() -> Result<()> {
let cookie = web_sys::window()?
.document()?
.dyn_into<web_sys::HtmlDocument>()?
.cookie()?;
Ok(())
}
It's the same number of lines, but less boilerplate and for simpler cases a one-liner.
If you really don't want to return a result you can wrap the whole thing in a lambda, (or a try block if you're happy using unstable features).
pub fn start() {
let cookie = (|| Result<Cookie)> {
web_sys::window()?
.document()?
.dyn_into<web_sys::HtmlDocument>()?
.cookie()
}).unwrap();
}
if you find you don't like repeating this frequently - you can use functions
fn document() -> Result<Document> {
web_sys::window()?.document()
}
fn html() -> Result<web_sys::HtmlDocument> {
document()?.dyn_into<web_sys::HtmlDocument>()
}
fn cookie() -> Result<Cookie> {
html()?.cookie()
}
pub fn start() {
let cookie = cookie()?;
}
That's unpractical and bothers me.
Unsure what's your issue here, but if you access the same cookie again and again in your application, perhaps you can save it in a struct and just use that struct? In my recent WebAssembly project I saved some of the elements I've used in a struct and used them by passing it around.
I also think that perhaps explaining your specific use case might lead to more specific answers :)

Why do I get the error "function pointers in const fn are unstable" but it goes away when wrapped in a newtype?

Is this intended behaviour or a compiler bug?
The following code does not compile. values in MyStruct is an Option since Vec::new is not a const fn - but Option::None is constant (but it still does not compile).
type MyFun = fn(input: u32) -> u32;
struct MyStruct {
values: Option<Vec<MyFun>>,
}
impl MyStruct {
pub const fn init() -> Self {
Self { values: None }
}
}
fn main() {
MyStruct::init();
}
Playground
error[E0723]: function pointers in const fn are unstable
--> src/main.rs:9:24
|
9 | Self { values: None }
| ^^^^
|
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
= help: add `#![feature(const_fn)]` to the crate attributes to enable
Using a newtype (Wrapped) solves the problem. This feels strange, since both examples are identical (at least the generated binaries should be identical). Is this behaviour intended or is that a bug?
This works:
type MyFun = fn(input: u32) -> u32;
struct Wrapped(Vec<MyFun>);
struct MyStruct {
values: Option<Wrapped>,
}
impl MyStruct {
pub const fn init() -> Self {
Self { values: None }
}
}
fn main() {
MyStruct::init();
}
Playground
TLDR: A bug, but not the one you were hinting at. We are overaggressive in keeping the door open for future features in const fn.
The error you are encountering was created in order to prevent users from writing functions like
const fn foo(f: fn()) {}
since it is impossible to use f in a callable way. The following function is illegal right now.
const fn foo(f: fn()) { f() }
At the time of stabilization of const fn we weren't sure whether it should be legal, so we preemptively forbade fn pointers in const fn. The same goes for creating function pointers within the const fn. So
const fn foo() {
let f: fn() = some_function;
}
is forbidden, because we want to keep the door open for permitting
const fn foo() {
let f: fn() = some_function;
f();
}
If you expand your use case's code, you get something like
pub const fn init() -> Self {
let values: Option<fn(u32) -> u32> = None;
Self { values }
}
You are correct in that this is a bug. Though not due the difference between the wrapped and non-wrapped version, but because the None never actually creates a function pointer. We just decided to be overly aggressive in the check in order to not miss anything. It is definitely possible to create a better analysis here, though we may just want to implement function pointers within const fn.
The reason there's a difference between the wrapped and non-wrapped version is that we want to allow
const fn foo(f: fn()) { f() }
but not
const fn foo(wrapper: Wrapper) { (wrapper.f)() }
as the latter doesn't show the function pointer in the API, so we can't do any magic to ensure that the function pointer points to a const fn.
The difference between the wrapped and non-wrapped version may be confusing enough to force us to abandon the idea that we can just invoke fn pointers in const fn as described above and come up with a new scheme for fn pointers in const fn.

Is there a way to get the file and the module path of where a procedural macro is attached at compile-time?

I'm looking for the equivalent of file!() & module_path!() in a procedural macro context.
For example, the following doesn't work:
file.rs:
#[some_attribute]
const A: bool = true;
macro.rs:
#[proc_macro_attribute]
pub fn some_attribute(attr: TokenStream, input: TokenStream) -> TokenStream {
println!("{}", file!());
input
}
This prints macro.rs which makes sense, but what I want is file.rs. Is there a way to achieve this? Is there also a similar way for module_path!()?
A requirement of this is that has to happen at compile-time.
I'm trying to create a file in the OUT_DIR containing constant values where the attribute is added with the module and the file that they are in.
I had the same problem and found out that Rust added a new experimential API to Rust macros (#54725) which allows exaclty what you want:
#![feature(proc_macro_span)]
#[proc_macro]
pub(crate) fn do_something(item: TokenStream) -> TokenStream {
let span = Span::call_site();
let source = span.source_file();
format!("println!(r#\"Path: {}\"#)", source.path().to_str().unwrap())
.parse()
.unwrap()
}
use my_macro_crate::*;
fn main() {
println!("Hello, world!");
do_something!();
}
Will output:
Hello, world!
Path: src\main.rs
Important
Apart from this API being experimential, the path might not be a real OS path. This can be the case if the Span was generated by a macro. Visit the documentation here.
The problem here is that println!("{}", file!()); is executed at compile time and not at runtime. Similar to an answer that was recently given here, you can edit the original function and insert your code at the beginning of it, which will be executed at runtime this time. You can still use the procedural macros file!() and module_path!(). Here is a macro.rs with this approach:
#[proc_macro_attribute]
pub fn some_attribute(_attr: TokenStream, input: TokenStream) -> TokenStream {
// prefix to be added to the function's body
let mut prefix: TokenStream = "
println!(\"Called from {:?} inside module path {:?}\",
file!(), module_path!());
".parse().unwrap();
// edit TokenStream
input.into_iter().map(|tt| {
match tt {
TokenTree::Group(ref g) // match function body
if g.delimiter() == proc_macro::Delimiter::Brace => {
// add logic before function body
prefix.extend(g.stream());
// return new function body as TokenTree
TokenTree::Group(proc_macro::Group::new(
proc_macro::Delimiter::Brace, prefix.clone()))
},
other => other, // else just forward
}
}).collect()
}
You can use it like this in your main.rs:
use mylib::some_attribute;
#[some_attribute]
fn yo() -> () { println!("yo"); }
fn main() { yo(); }
Note that the code is added before what's inside of the function's body. We could have inserted it at the end, but this would break the possibility of returning a value without a semicolon.
EDIT: Later realized that the OP wants it to run at compile time.

How best to deal with struct field that can change types

I'm working with a library that uses Rust types to keep track of state. As a simplified example, say you have two structs:
struct FirstStruct {}
struct SecondStruct {}
impl FirstStruct {
pub fn new() -> FirstStruct {
FirstStruct {}
}
pub fn second(self) -> SecondStruct {
SecondStruct {}
}
// configuration methods defined in this struct
}
impl SecondStruct {
pub fn print_something(&self) {
println!("something");
}
pub fn first(self) -> FirstStruct {
FirstStruct {}
}
}
And to actually use these structs you usually follow a pattern like so, after printing you may stay in second state or go back to first state depending on how you're using the library:
fn main() {
let first = FirstStruct::new();
let second = first.second(); // consumes first
second.print_something();
// go back to default state
let _first = second.first();
}
I want to create my own struct that handles the state changes internally and simplifies the interface. This also lets me have a single mutable reference around that I can pass to other functions and call the print method. Using it should look something like this:
fn main() {
let mut combined = CombinedStruct::new(FirstStruct::new());
combined.print();
}
I've come up with the following solution that works, at least in this simplified example:
enum StructState {
First(FirstStruct),
Second(SecondStruct),
}
struct CombinedStruct {
state: Option<StructState>,
}
impl CombinedStruct {
pub fn new(first: FirstStruct) -> CombinedStruct {
CombinedStruct {
state: Some(StructState::First(first)),
}
}
pub fn print(&mut self) {
let s = match self.state.take() {
Some(s) => match s {
StructState::First(first) => first.second(),
StructState::Second(second) => second,
},
None => panic!(),
};
s.print_something();
// If I forget to do this, then I lose access to my struct
// and next call will panic
self.state = Some(StructState::First(s.first()));
}
}
I'm still pretty new to Rust but this doesn't look right to me. I'm not sure if there's a concept I'm missing that could simplify this or if this solution could lead to ownership problems as my application gets more complicated. Is there a better way to do this?
Playground link
I once had a similar problem and went basically with your solution, but I avoided the Option.
I.e. I basically kept your
enum StructState {
First(FirstStruct),
Second(SecondStruct),
}
If an operation tries to convert a FirstStruct to a SecondStruct, I introduced a function try_to_second roughly as follows:
impl StructState {
fn try_to_second(self) -> Result<SecondState, StructState> {
/// implementation
}
}
In this case, an Err indicates that the StructState has not been converted to SecondStruct and preserves the status quo, while an Ok value indicates successfull conversion.
As an alternative, you could try to define try_to_second on FirstStruct:
impl FirstStruct {
fn try_to_second(self) -> Result<FirstStruct, SecondStruct> {
/// implementation
}
}
Again, Err/Ok denote failure/success, but in this case, you have more concrete information encoded in the type.

How to programmatically get the number of fields of a struct?

I have a custom struct like the following:
struct MyStruct {
first_field: i32,
second_field: String,
third_field: u16,
}
Is it possible to get the number of struct fields programmatically (like, for example, via a method call field_count()):
let my_struct = MyStruct::new(10, "second_field", 4);
let field_count = my_struct.field_count(); // Expecting to get 3
For this struct:
struct MyStruct2 {
first_field: i32,
}
... the following call should return 1:
let my_struct_2 = MyStruct2::new(7);
let field_count = my_struct2.field_count(); // Expecting to get count 1
Is there any API like field_count() or is it only possible to get that via macros?
If this is achievable with macros, how should it be implemented?
Are there any possible API like field_count() or is it only possible to get that via macros?
There is no such built-in API that would allow you to get this information at runtime. Rust does not have runtime reflection (see this question for more information). But it is indeed possible via proc-macros!
Note: proc-macros are different from "macro by example" (which is declared via macro_rules!). The latter is not as powerful as proc-macros.
If this is achievable with macros, how should it be implemented?
(This is not an introduction into proc-macros; if the topic is completely new to you, first read an introduction elsewhere.)
In the proc-macro (for example a custom derive), you would somehow need to get the struct definition as TokenStream. The de-facto solution to use a TokenStream with Rust syntax is to parse it via syn:
#[proc_macro_derive(FieldCount)]
pub fn derive_field_count(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as ItemStruct);
// ...
}
The type of input is ItemStruct. As you can see, it has the field fields of the type Fields. On that field you can call iter() to get an iterator over all fields of the struct, on which in turn you could call count():
let field_count = input.fields.iter().count();
Now you have what you want.
Maybe you want to add this field_count() method to your type. You can do that via the custom derive (by using the quote crate here):
let name = &input.ident;
let output = quote! {
impl #name {
pub fn field_count() -> usize {
#field_count
}
}
};
// Return output tokenstream
TokenStream::from(output)
Then, in your application, you can write:
#[derive(FieldCount)]
struct MyStruct {
first_field: i32,
second_field: String,
third_field: u16,
}
MyStruct::field_count(); // returns 3
It's possible when the struct itself is generated by the macros - in this case you can just count tokens passed into macros, as shown here. That's what I've come up with:
macro_rules! gen {
($name:ident {$($field:ident : $t:ty),+}) => {
struct $name { $($field: $t),+ }
impl $name {
fn field_count(&self) -> usize {
gen!(#count $($field),+)
}
}
};
(#count $t1:tt, $($t:tt),+) => { 1 + gen!(#count $($t),+) };
(#count $t:tt) => { 1 };
}
Playground (with some test cases)
The downside for this approach (one - there could be more) is that it's not trivial to add an attribute to this function - for example, to #[derive(...)] something on it. Another approach would be to write the custom derive macros, but this is something that I can't speak about for now.

Resources