How to name an arbitrary sequence of things in a macro? - macros

I am trying to use ? in a macro, matching an arbitrary keyword:
#![feature(macro_at_most_once_rep)]
macro_rules! foo {
(
pub fn $name:ident (
& $m : $( mut )? self
)
) => (
pub fn $name (
& $m self
) {}
)
}
struct Foo;
impl Foo {
foo!( pub fn bar(&mut self) );
foo!( pub fn baz(&self) );
}
fn main() {}
I tried varied syntax, but they all failed. How to do this?

One trick would be to insert a repetition with a dummy token.
#![feature(macro_at_most_once_rep)]
macro_rules! foo {
(
pub fn $name:ident (
& $( $(#$m:tt)* mut )? self
)
) => (
pub fn $name (
& $( $(#$m)* mut )? self
) {}
)
}
struct Foo;
impl Foo {
foo!( pub fn bar(&mut self) );
foo!( pub fn baz(&self) );
}
fn main() {
(&mut Foo).bar();
(&mut Foo).baz();
// (&Foo).bar(); //~ERROR cannot borrow
(&Foo).baz();
}

Related

Making a raw sql-query in Rust Diesel

I need to query a function in Postgresql (14) using diesel. I already have queries that works on tables and views. This works, a view in this case.
schema.rs:
table! {
latest_readings {
measurement_time_default -> Timestamptz,
id -> Integer,
data -> Jsonb,
}
}
models.rs:
#[derive(Serialize, Queryable)]
pub struct LatestReading {
#[diesel(deserialize_as = "MyDateTimeWrapper")]
pub measurement_time_default: DateTime<Local>,
pub id: i32,
pub data: serde_json::Value,
}
controller.rs:
pub async fn get_readings(db: web::Data<Pool>) -> Result<HttpResponse, Error> {
Ok(web::block(move || db_get_readings(db))
.await
.map(|reading| HttpResponse::Ok().json(reading))
.map_err(|_| HttpResponse::InternalServerError())?)
}
fn db_get_readings(pool: web::Data<Pool>) -> Result<Vec<LatestReading>, diesel::result::Error> {
let conn = pool.get().unwrap();
latest_readings.load::<LatestReading>(&conn)
}
This won't compile. The part that call the postgresql-function.
schema.rs:
table! {
measurements_single_location_function {
id -> Integer,
name -> Text,
latitude -> Numeric,
longitude -> Numeric,
measurement_time_default -> Timestamptz,
measurements -> Jsonb,
}
}
models.rs:
#[derive(Serialize, Queryable, QueryableByName)]
#[table_name = "measurements_single_location_function"]
pub struct MeasurementsSingleLocation {
pub id: i32,
pub name: String,
pub latitude: BigDecimal,
pub longitude: BigDecimal,
#[diesel(deserialize_as = "MyDateTimeWrapper")]
pub measurement_time_default: DateTime<Local>,
pub measurements: serde_json::Value,
}
DB-query in controllers.rs:
fn db_get_measurements_single_location(
pool: web::Data<Pool>,
location_id: i32,
rows: i32,
) -> QueryResult<Vec<MeasurementsSingleLocation>> {
let conn = pool.get().unwrap(); // Error on next line
let result: QueryResult<Vec<MeasurementsSingleLocation>> =
sql_query("select * from measurements_single_location_function(1,10)")
.load::<MeasurementsSingleLocation>(&conn);
return result;
}
The compile-error:
Compiling weather_rest v0.1.0 (/Users/claus/devel/rust/vegvesen/weather_rest)
error[E0277]: the trait bound `SqlQuery: LoadQuery<_, MeasurementsSingleLocation>` is not satisfied
--> src/controller.rs:141:14
|
141 | .load::<MeasurementsSingleLocation>(&conn);
| ^^^^ the trait `LoadQuery<_, MeasurementsSingleLocation>` is not implemented for `SqlQuery`
|
= help: the following implementations were found:
<SqlQuery as LoadQuery<Conn, T>>
note: required by a bound in `load`
--> /Users/claus/.cargo/registry/src/github.com-1ecc6299db9ec823/diesel-1.4.6/src/query_dsl/mod.rs:1238:15
|
1238 | Self: LoadQuery<Conn, U>,
| ^^^^^^^^^^^^^^^^^^ required by this bound in `load`
I am not able to see what I am missing here.
Cargo.toml:
diesel = { version = "1.4.6", features = ["postgres", "uuidv07", "r2d2", "chrono", "numeric", "serde_json"] }
I recently wrote a backend-service for another project using this excellent example as a template. I applied the same structure to this and it now compiles.
schema.rs:
table! {
measurements_single_location_function {
id -> Integer,
name -> Text,
latitude -> Text,
longitude -> Text,
measurement_time_default -> Timestamptz,
measurements -> Jsonb,
}
}
routes.rs:
#[get("/measurements_single_location/{id}/{rows}")]
async fn measurements_single_location(path: web::Path<(i32, i32)>) -> Result<HttpResponse, CustomError> {
let (id, rows) = path.into_inner();
let m = MeasurementsSingleLocation::measurements_single_location(id, rows)?;
Ok(HttpResponse::Ok().json(m))
}
pub fn init_routes(config: &mut web::ServiceConfig) {
config.service(measurements_single_location);
}
models.rs:
#[derive(Serialize, QueryableByName)]
#[table_name = "measurements_single_location_function"]
pub struct MeasurementsSingleLocation {
pub id: i32,
pub name: String,
pub latitude: String,
pub longitude: String,
pub measurement_time_default: NaiveDateTime,
pub measurements: serde_json::Value,
}
impl MeasurementsSingleLocation {
pub fn measurements_single_location(id: i32, rows: i32) -> Result<Vec<MeasurementsSingleLocation>, CustomError> {
let q = "select * from measurements_single_location_function($1,$2)";
let mut conn = db::connection()?;
let m= diesel::sql_query(q)
.bind::<Integer, _>(id)
.bind::<Integer, _>(rows)
.get_results(&mut conn)?;
Ok(m)
}
}

"expected struct String, found struct schema::my_table::columns::my_column" when trying to insert value with Diesel

I am trying to execute an insert multiple columns using Diesel with PostgreSQL.
This is the insert function to add a new Project -
pub fn insert(project: NewProject, program_id: i32, conn: &PgConnection) -> bool {
use schema::projects::dsl::*;
use schema::projects::dsl::{title as t};
use schema::projects::dsl::{program_id as prog_id};
let NewProject {
title
} = project;
diesel::insert_into(projects)
.values((t.eq(title), prog_id.eq(program_id)))
.execute(conn)
.is_ok()
}
And Project and NewProject
#[derive(Queryable, Serialize, Debug, Clone)]
pub struct Project {
pub id: i32,
pub title: String,
pub program_id: i32,
pub is_archived: bool
}
#[derive(Serialize, Deserialize, Insertable)]
#[table_name = "projects"]
pub struct NewProject {
pub title: String
}
And the projects table looks like this -
CREATE TABLE projects (
id SERIAL PRIMARY KEY,
title VARCHAR NOT NULL,
program_id INTEGER NOT NULL REFERENCES programs (id),
is_archived BOOLEAN NOT NULL DEFAULT FALSE
);
and the schema.rs -
table! {
projects (id) {
id -> Int4,
title -> Varchar,
program_id -> Int4,
is_archived -> Bool,
}
When compiled I get an error saying -
title | ^^^^^ expected struct std::string::String,
found struct schema::projects::columns::title
and
.execute(conn) | ^^^^^^^ expected struct
diesel::query_source::Never, found struct
diesel::query_source::Once
I do not get a compile error when I do
.values(&project)
in the insert function instead.
Here is a MCVE of your problem:
#[macro_use]
extern crate diesel;
use diesel::pg::PgConnection;
use diesel::prelude::*;
mod schema {
table! {
projects (id) {
id -> Int4,
title -> Varchar,
program_id -> Int4,
is_archived -> Bool,
}
}
#[derive(Debug, Insertable)]
#[table_name = "projects"]
pub struct NewProject {
pub title: String,
}
}
use schema::NewProject;
fn insert(project: NewProject, program_id: i32, conn: &PgConnection) -> bool {
use schema::projects::dsl::*;
use schema::projects::dsl::{title as t};
use schema::projects::dsl::{program_id as prog_id};
let NewProject {
title
} = project;
diesel::insert_into(projects)
.values((t.eq(title), prog_id.eq(program_id)))
.execute(conn)
.is_ok()
}
fn main() {}
You have imported a type called title that conflicts with the destructuring, as the error message states:
error[E0308]: mismatched types
--> src/main.rs:34:22
|
34 | let NewProject { title } = project;
| ^^^^^ expected struct `std::string::String`, found struct `schema::projects::columns::title`
|
= note: expected type `std::string::String`
found type `schema::projects::columns::title`
This can be reduced to a very small case:
struct foo;
struct Thing { foo: String }
fn example(t: Thing) {
let Thing { foo } = t;
}
error[E0308]: mismatched types
--> src/lib.rs:5:17
|
5 | let Thing { foo } = t;
| ^^^ expected struct `std::string::String`, found struct `foo`
|
= note: expected type `std::string::String`
found type `foo`
Note that this struct is defined without curly braces, which makes it a unit-like struct. These are convenient, but they have the subtle nuance that they create both a type and a value:
struct foo;
fn example() {
let foo: foo = foo;
// ^-- the only value of the type `foo`
// ^-------- the type `foo`
// ^------------- newly-defined unrelated identifier
}
When destructuring, the pattern is preferred as a type, not an identifier.
Don't import that type and you won't have a conflict:
fn insert(project: NewProject, program_id: i32, conn: &PgConnection) -> bool {
use schema::projects::dsl;
let NewProject { title } = project;
diesel::insert_into(dsl::projects)
.values((dsl::title.eq(title), dsl::program_id.eq(program_id)))
.execute(conn)
.is_ok()
}

"cannot find value `a` in this scope" in Rust macro

I created macro for printing, using proc-macro-hack.
Then this error occured though I already have defined a.
Following is the code.
On decl crate,
proc_macro_expr_decl! {
/// Function for printing to the standard output.
///
/// First argument can be literal or not literal.
gprint! => gprint_impl
}
On impl crate,
use syn::{Expr, ExprTuple, parse_str};
use quote::ToTokens;
fn _print_impl(input: &str, print_name: &str) -> String {
let mut input_with_parens = String::with_capacity(input.len() + 2);
input_with_parens.push('(');
input_with_parens.push_str(input);
input_with_parens.push(')');
let tuple = parse_str::<ExprTuple>(&input_with_parens)
.unwrap_or_else(|_| panic!("expected arguments is expressions separated by comma, found {}", input))
let mut arg_iter = tuple.elems.iter();
let first = arg_iter.next();
if first.is_none() {
return "()".to_string();
}
let first = first.unwrap();
let mut s = String::new();
if let &Expr::Lit(ref lit) = first {
s.push_str(print_name);
s.push('(');
s.push_str(&lit.into_tokens().to_string());
} else {
s.push_str(print_name);
s.push_str("(\"{}\", ");
s.push_str(&first.into_tokens().to_string());
}
for arg in arg_iter {
s.push_str(", ");
s.push_str(&arg.into_tokens().to_string());
}
s.push(')');
s
}
proc_macro_expr_impl! {
pub fn gprint_impl(input: &str) -> String {
_print_impl(input, "print!")
}
}
And tried using this macro,
fn main() {
let a = 0;
gprint!(a);
}
error occured:
error[E0425]: cannot find value `a` in this scope
Why?

How do I create a Rust macro to define a String variable with the value of its own identifier?

I want to write a macro to define something like below:
let FOO: String = "FOO".to_string();
It is possible for me to have a macro:
macro_rules! my_macro {
($name: ident, $val: expr) => {
let $name: String = $val.to_string();
}
}
and use it as my_macro!(FOO, "FOO");
However, this is a bit redundant. I expect to have something like my_macro!(FOO), and it can expand and use the $name as identifier, but also in the string value.
You want stringify!:
macro_rules! str_var {
($name:ident) => {
let $name = String::from(stringify!($name));
};
}
fn main() {
str_var!(foo);
println!("foo: {:?}", foo);
}

How to pass anonymous functions as parameters in Rust?

I've been playing around with Rust the past week. I can't seem to figure out how to pass a function that is defined as a parameter when calling the method, and haven't come across any documentation that shows them being used in that fashion.
Is it possible to define a function in the parameter list when calling a function in Rust?
This is what I've tried so far...
fn main() {
// This works
thing_to_do(able_to_pass);
// Does not work
thing_to_do(fn() {
println!("found fn in indent position");
});
// Not the same type
thing_to_do(|| {
println!("mismatched types: expected `fn()` but found `||`")
});
}
fn thing_to_do(execute: fn()) {
execute();
}
fn able_to_pass() {
println!("Hey, I worked!");
}
In Rust 1.0, the syntax for closure parameters is as follows:
fn main() {
thing_to_do(able_to_pass);
thing_to_do(|| {
println!("works!");
});
}
fn thing_to_do<F: FnOnce()>(func: F) {
func();
}
fn able_to_pass() {
println!("works!");
}
We define a generic type constrained to one of the closure traits: FnOnce, FnMut, or Fn.
Like elsewhere in Rust, you can use a where clause instead:
fn thing_to_do<F>(func: F)
where F: FnOnce(),
{
func();
}
You may also want to take a trait object instead:
fn main() {
thing_to_do(&able_to_pass);
thing_to_do(&|| {
println!("works!");
});
}
fn thing_to_do(func: &Fn()) {
func();
}
fn able_to_pass() {
println!("works!");
}