I want to implement a static cache in rust.
I tried chashmap
extern crate chashmap;
extern crate lazy_static;
use chashmap::{CHashMap, ReadGuard};
use lazy_static::lazy_static;
use std::collections::HashMap;
struct Data {}
#[derive(Default)]
struct Merged {
types: HashMap<String, Data>,
}
fn merge(ls: &[String]) -> ReadGuard<'static, Vec<String>, Merged> {
lazy_static! {
static ref CACHE: CHashMap<Vec<String>, Merged> = Default::default();
}
let libs = ls.to_vec();
let merged = Merged::default();
CACHE.insert(libs, merged);
return CACHE.get(ls).unwrap();
}
fn get<'a>(ls: &[String], name: &str) -> Option<&'a Data> {
let lib = merge(ls);
if let Some(ty) = lib.types.get(name) {
return Some(&*ty);
}
None
}
fn main() {}
[package]
name = "stackoverflow-56728860"
version = "0.1.0"
authors = ["강동윤 <kdy1#outlook.kr>"]
edition = "2018"
[dependencies]
lazy_static = "1"
chashmap = "2"
github repo
But I want to return static reference to data from the function. The returned data solely depends on ls. That is, if input (ls) is same, the result would be same.
Also, leaking data is ok if read lock is released.
I somehow solved it with leaking.
fn merge(ls: &[Lib]) -> &'static Merged {
lazy_static! {
static ref CACHE: CHashMap<Vec<Lib>, &'static Merged> = Default::default();
}
// ...
CACHE.insert(libs, Box::leak(merged));
return &*CACHE.get(ls).unwrap();
}
Related
Take for example the Rust library lazy_static's example:
use lazy_static::lazy_static;
use std::collections::HashMap;
lazy_static! {
static ref HASHMAP: HashMap<u32, &'static str> = {
let mut m = HashMap::new();
m.insert(0, "foo");
m.insert(1, "bar");
m.insert(2, "baz");
m
};
static ref COUNT: usize = HASHMAP.len();
static ref NUMBER: u32 = times_two(21);
}
How might this be done in Zig?
I have tried this which is the only thing that makes sense to me:
const std = #import("std");
pub fn main() void {
comptime var h = std.StringHashMap(i32).init(std.testing.allocator);
h.put("hi", 5) catch {};
std.debug.print("{}", .{h});
}
but this segfaults.
Is it even possible to do this in Zig?
It seems (thanks to this Reddit post) that this is implemented in the standard library
and can be used via std.ComptimeStringMap
This however does not seem to support any dynamic insertion as there is no insert method.
How can I create a new vector with the iterator Rust macro syntax?
I am trying this:
unsafe {
MUT_STATIC_VAR = vec![
#(#my_outher_vector_data)*,
];
}
Full explanation: I am trying to reasign data that I write in one mut static var of type: Vec when the macro it's spanded at compile time. When I try to retrieve the data at runtime, the global it's empty, so I am rewiring the data that I want in main().
Recap. I am just want to assign the content of one vector to another, but neither array or Vec<T> implements ToTokens.
Compiler error:
`main` function not found in crate `my_crate`
Thanks
To initialize the content, Iterators are able to use macro #(#...)*, syntax.
let other_as_iter = my_outher_vector_data.iter();
quote {
unsafe {
MUT_STATIC_VAR = vec![
#(#other_as_iter)*,
];
}
}
I think lazy_static should do the job:
#[macro_use]
extern crate lazy_static;
use std::sync::Mutex;
lazy_static! {
static ref MUT_STATIC_VAR: Mutex<Vec<String>> = Mutex::new(vec![]);
}
fn other_vec(v: Vec<String>) {
let mut r = MUT_STATIC_VAR.lock().unwrap();
r.extend_from_slice(v.as_slice());
}
fn main() {
other_vec(vec!["dog".to_string(), "cat".to_string(), "mouse".to_string()]);
}
…or draining the other vec after initializing MUT_STATIC_VAR:
fn other_vec(v: &mut Vec<String>) {
let mut r = MUT_STATIC_VAR.lock().unwrap();
r.extend_from_slice(v.drain(..).as_slice());
}
fn main() {
other_vec(&mut vec!["dog".to_string(), "cat".to_string(), "mouse".to_string()]);
}
…or my_other_vector_data wrapped in other_vec! macro:
Playground
macro_rules! other_vec {
() => {
vec!["dog", "cat", "mouse"] // my_other_vector_data here
};
}
Is there a way in Rust to get the "calling" function name or any other contextual information inside a macro?
Example:
#[macro_export]
macro_rules! somemacro {
( $x:expr ) => {
{
// access function name (etc..) that called this macro
}
};
}
This can be done using a procedural macro:
extern crate proc_macro;
use proc_macro::TokenStream;
#[proc_macro_attribute]
pub fn with_name(_: TokenStream, item: TokenStream) -> TokenStream {
let mut input = syn::parse_macro_input!(item as syn::ItemFn);
let fn_name = input.ident.to_string();
let const_decl = quote::quote! {
const THIS_FN: &str = #fn_name;
};
input.block.stmts.insert(0, syn::parse(const_decl.into()).unwrap());
let output = quote::quote! {
#input
};
output.into()
}
Cargo.toml:
[package]
name = "with_name"
version = "0.1.0"
edition = "2018"
[lib]
proc-macro = true
[dependencies]
quote = "0.6.12"
syn = { version = "0.15.37", features = ["full"] }
Which can be used as:
#[with_name::with_name]
fn foo() {
println!("Name: {}", THIS_FN);
}
fn main() {
foo();
}
Also note that if you only care about the module, there is a built-in macro for that:
mod test {
pub fn foo() {
println!("Module: {}", module_path!());
}
}
fn main() {
test::foo();
}
(link to playground)
How would you alter the example from Rocket's website to take a date rather than an age/u8?
The example from the website:
#![feature(proc_macro_hygiene, decl_macro)]
#[macro_use] extern crate rocket;
#[get("/hello/<name>/<age>")]
fn hello(name: String, age: u8) -> String {
format!("Hello, {} year old named {}!", age, name)
}
fn main() {
rocket::ignite().mount("/", routes![hello]).launch();
}
I'd like to have more or less the same output (Hello, 58 year old named John!) but have something like this
#[get("/hello/<name>/<birthdate>")]
instead of that
#[get("/hello/<name>/<age>")]
I think the right struct is chrono::DateTime and that somehow rocket::request::FromParam is involved but I'm a bit lost from there.
Kinda sucks that we have to do this ourselves.
Maybe in the future, there will be a library provided which gives us interop between Rocket and other libraries.
use chrono::NaiveDate;
use chrono::NaiveTime;
use chrono::NaiveDateTime;
// https://stackoverflow.com/questions/25413201/how-do-i-implement-a-trait-i-dont-own-for-a-type-i-dont-own
// https://github.com/SergioBenitez/Rocket/issues/602#issuecomment-380497269
pub struct NaiveDateForm(NaiveDate);
pub struct NaiveTimeForm(NaiveTime);
pub struct NaiveDateTimeForm(NaiveDateTime);
impl<'v> FromFormValue<'v> for NaiveDateForm {
type Error = &'v RawStr;
fn from_form_value(form_value: &'v RawStr) -> Result<NaiveDateForm, &'v RawStr> {
let decoded = form_value.url_decode().map_err(|_| form_value)?;
if let Ok(date) = NaiveDate::parse_from_str(&decoded, "%Y-%m-%d") {
return Ok(NaiveDateForm(date));
}
Err(form_value)
}
}
impl<'v> FromFormValue<'v> for NaiveTimeForm {
type Error = &'v RawStr;
fn from_form_value(form_value: &'v RawStr) -> Result<Self, Self::Error> {
let decoded = form_value.url_decode().map_err(|_| form_value)?;
if let Ok(time) = NaiveTime::parse_from_str(&decoded, "%H:%M:%S%.3f") {
// if time.nanosecond() >= 1_000_000_000 {
// return Err(form_value);
// }
return Ok(NaiveTimeForm(time));
}
if let Ok(time) = NaiveTime::parse_from_str(&decoded, "%H:%M") {
return Ok(NaiveTimeForm(time));
}
Err(form_value)
}
}
impl<'v> FromFormValue<'v> for NaiveDateTimeForm {
type Error = &'v RawStr;
fn from_form_value(form_value: &'v RawStr) -> Result<NaiveDateTimeForm, &'v RawStr> {
let decoded = form_value.url_decode().map_err(|_| form_value)?;
if decoded.len() < "0000-00-00T00:00".len() {
return Err(form_value)
}
let date = NaiveDateForm::from_form_value(RawStr::from_str(&decoded[.."0000-00-00".len()]))
.map_err(|_| form_value)?;
let time = NaiveTimeForm::from_form_value(RawStr::from_str(&decoded["0000-00-00T".len()..]))
.map_err(|_| form_value)?;
Ok(NaiveDateTimeForm(NaiveDateTime::new(*date, *time)))
}
}
impl Deref for NaiveDateForm {
type Target = NaiveDate;
fn deref(&self) -> &NaiveDate {
&self.0
}
}
impl Deref for NaiveTimeForm {
type Target = NaiveTime;
fn deref(&self) -> &NaiveTime {
&self.0
}
}
impl Deref for NaiveDateTimeForm {
type Target = NaiveDateTime;
fn deref(&self) -> &NaiveDateTime {
&self.0
}
}
You should then be able to do:
#[get("/hello/<name>/<age>")]
fn hello(name: String, age: NaiveDateTimeForm) -> String {
// Deref back to chrono::NaiveDatetime
let date_time = *age;
// write some code to figure out their age
}
My dependencies:
chrono = { version = "0.4.19", features = ["serde"] }
rocket = "0.4.2"
This implementation is mostly stolen from https://github.com/chronotope/chrono/pull/362/files where someone made a PR to try to get this stuff already into Chrono.
Probably rather than age, you should have birthday so you can calculate their age.
NaiveDate can be represented as "number of days since January 1, 1" with type i32. There are methods self.num_days_from_ce() and from_num_days_from_ce(). I believe this is the most convenient way. Documentation
i follow harvzor's code with a work version for rocket 0.5.
use chrono::NaiveDate;
use chrono::ParseError;
use rocket::request::FromParam;
// https://stackoverflow.com/questions/25413201/how-do-i-implement-a- trait-i-dont-own-for-a-type-i-dont-own
// https://github.com/SergioBenitez/Rocket/issues/602#issuecomment-380497269
pub struct NaiveDateForm(pub NaiveDate);
impl<'a> FromParam<'a> for NaiveDateForm {
type Error = ParseError;
fn from_param(param: &'a str) -> Result<Self, Self::Error>{
match NaiveDate::parse_from_str(¶m, "%Y-%m-%d") {
Ok(date)=> Ok(NaiveDateForm(date)),
Err(e) =>Err(e),
}
}
}
I want to call a Rust library which will create an object increment_engine for me and return a pointer to it (or anything persistent). This engine would be given a parameter on creation.
Later I could call this object's increment(a) method and it would add the remembered parameter to a and return the result. Here is the code:
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
public class App {
public interface MyLibrary extends Library {
MyLibrary INSTANCE = (MyLibrary) Native.loadLibrary("myjavarust", MyLibrary.class);
double addition(double a , double b);
int set_increment_engine(double parameter);
double use_increment_engine(int engine_id, double a);
}
public static void main() {
int sum = MyLibrary.INSTANCE.addition(13.0,5.0);
System.out.println(sum); // this works and prints 18 (=13+5)
engine_id = MyLibrary.INSTANCE.get_increment_engine(13.0);
double result = MyLibrary.INSTANCE.use_increment_engine(engine_id,5.0);
System.out.println(result); // this should also return 18
}
}
The last three lines of main() show how I would like to use the "increment engine"
The Rust pseudo-code should look like this.
extern crate libc;
use libc::{c_double, uint32_t};
#[no_mangle]
pub extern "C" fn addition(a: f64, b: f64) -> f64 {
a + b
}
#[no_mangle]
pub extern "C" fn set_increment_engine(param: c_double) -> uint32_t {
let engine = IncrementEngine { param: param };
return_engine_id_somehow
}
#[no_mangle]
pub extern "C" fn use_increment_engine(engine_id: uint32_t, a: c_double) -> c_double {
let engine = find_engine_somehow(engine_id);
engine.increment(a)
}
struct IncrementEngine {
param: c_double,
}
impl IncrementEngine {
pub fn increment(&self, a: f64) -> f64 {
a + self.param
}
}
I have successfully tested the function "addition" which does not require the persistent "increment machine", but I would like to use the engine pattern (obviously for more complex things than incrementing a double). I have investigated many sites about passing data across library boundaries and there is lots of information on passing structures etc, but not so many on "persistent pointers". The only thing close to the solution is in the Nomicon where the Rust library calls the caller back which allows for the object to persist, but it is really not applicable to my use-case.
engine_id in the example is an int, but presumably it would be some kind of pointer to the object created by set_increment_engine.
This approach can be taken:
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
public class App {
public interface MyLibrary extends Library {
MyLibrary INSTANCE = (MyLibrary) Native.loadLibrary("myjavarust", MyLibrary.class);
long set_increment_engine(double parameter);
double use_increment_engine(long engine, double a);
void free_increment_engine(long engine);
}
public static void main(String[] args) {
long engine = MyLibrary.INSTANCE.set_increment_engine(13.0);
double result = MyLibrary.INSTANCE.use_increment_engine(engine, 5.0);
System.out.println(result); // returns correctly 18.0
MyLibrary.INSTANCE.free_increment_engine(engine);
}
}
with this lib.rs code:
extern crate libc;
use libc::c_double;
#[no_mangle]
pub extern "C" fn set_increment_engine(param: c_double) -> *mut IncrementEngine {
let engine = IncrementEngine { param: param };
Box::into_raw(Box::new(engine))
}
#[no_mangle]
pub extern "C" fn use_increment_engine(engine_ptr: *mut IncrementEngine, a: c_double) -> c_double {
let engine = unsafe {
assert!(!engine_ptr.is_null());
&mut *engine_ptr
};
engine.increment(a)
}
#[no_mangle]
pub extern "C" fn free_increment_engine(engine_ptr: *mut IncrementEngine) {
if engine_ptr.is_null() {
return;
}
unsafe {
Box::from_raw(engine_ptr);
}
}
pub struct IncrementEngine {
param: c_double,
}
impl IncrementEngine {
pub fn increment(&self, a: f64) -> f64 {
a + self.param
}
}
Note that the function addition was removed as it only served for purpose of the question.