Rusteceans of the Fediverse, can you help me with a declarative macro problem?
-
@steffo@a.junimo.party That's supposed to become a mapping for fields in an sql database to rust enums and the strings are the actual table and column names in the database.
And now that you'Re asking I actually have an example implementation (generated by a lua script):
-
@slatian how can i get the identifiers for the enum variants of the fields?
like
Key,
MimeParameterId,
MimetypeId,
Value, -
@steffo@a.junimo.party That's the inner enums, so
FooBarFieldandFooBazFieldin my example above. -
Questo post è eliminato! -
@slatian where is SchemaName used then? is it
BaseTable? -
I've noticed, that I forgot to link a file, this one is where everything gets tied together:
https://codeberg.org/unobtanium/unobtanium/src/branch/main/lib-unobtanium/src/database/schemas.rs
-
@slatian yeah, that can be done, the only impossible thing is appending
Fieldto identifier names, as that would require a procedural macro (an external one would also work)shouldn't be an issue because in one case they're enums names and in the other they're enum variants, and the two can be disambiguated
-
@steffo@a.junimo.party In that case I think it would be easier to write the whole thing as a procedural macro?
-
@slatian unsure, give me a few mins and i'm (re)writing the macro_rules like that
-
@steffo@a.junimo.party Sorry, I haven't touched that code in quite a while … And I also didn't expect anyone to dive in this deep :drgn_heart:
The Declaration for my example would be:
sql_schema!{ BaseTable enum MimeParameter = "mime_parameter" { Key = "key", MimeParameterId = "mime_parameter_id", // … } enum Mimetype = "mimetype" { // … } enum Origin = "origin" { // … } // … } -
@slatian something like this?
pub trait Table {
fn sql_safe_table_name(&self) -> &'static str;
}
pub trait Field {
fn sql_safe_field_name(&self) -> &'static str;
}
macro_rules! sql_schema {
{
$schema_name:ident,
$(
enum $table_name:ident = $table_value:literal {
$( $field_name:ident = $field_value:literal ),*
}
)*
} => {
pub enum $schema_name {
$( $table_name ),*
}
impl Table for $schema_name {
fn sql_safe_table_name(&self) -> &'static str {
match self {
$( $schema_name::$table_name => $table_value ),*
}
}
}
$(
// it's not possible to concatenate things to identifiers without the use of a proc macro
// so we just re-use $table_name
pub enum $table_name {
$( $field_name ),*
}
impl Field for $table_name {
fn sql_safe_field_name(&self) -> &'static str {
match self {
$( $table_name::$field_name => $field_value ),*
}
}
}
)*
}
}
sql_schema! {
BaseTable,
enum MimeParameter = "mime_parameter" {
Key = "key",
MimeParameterId = "mime_parameter_id"
}
enum Mimetype = "mimetype" {
Charset = "charset"
// …
}
}you can use
cargo expandto see what it generates -
@steffo@a.junimo.party It took a while for me to wrap my Brain around this :drgn_sparkle: <- didn't expect it to be that … simple and especially readable.
Given that I can almost 1:1 copy this into criterium (licensed
LGPL-3.0-only): May I? If yes, what name do you want in the copyright header? -
@slatian sure! you can add
Stefano Pigozzi <me@steffo.eu>to thecontributorssection ofCargo.tomlif you want, but dw, it's just a snippet of code that fit in a fedi post
-
@slatian a thing to be aware of,
$(),*does not allow trailing commas, so this would workenum Mimetype = "mimetype" {
Charset = "charset"
}but this would give a weird error
enum Mimetype = "mimetype" {
Charset = "charset",
} -
The optional comma could just be eaten by a
$(…),* $(,)?Or am I missing something? (I don't write a lot of macros.)
-
@slatian yep
-
Questo post è eliminato! -
Questo post è eliminato! -
@slatian wait no i remembered correctly
-
This is what I ended up with:
https://codeberg.org/unobtanium/criterium/src/branch/main/src/sql/schema_macro.rs
Huge Thank You goes to @steffo@a.junimo.party :drgn_heart:
-
S steffo@a.junimo.party shared this topic on