2 ms·
Here's a real-world example from the code I was working on yesterday: I have several database tables where the records have numeric IDs, and instead of having t
by majewsky 7y ago
Here's a real-world example from the code I was working on yesterday: I have several database tables where the records have numeric IDs, and instead of having the ID type be just an int everywhere, I want them to be proper types to avoid mixups. Instead of
fn set_document_owner(document_id: i64, user_id: i64)
where I could easily provide the arguments in the wrong order, I want
fn set_document_owner(document_id: DocumentID, user_id: UserID)
where this cannot happen. Each ID type is just a one-element tuple containing an i64, which would just be
pub struct DocumentID(pub i64);
pub struct UserID(pub i64);
//... and so on ...
and so on. But in order for them to behave as expected (e.g. with the == operator or when reading/writing IDs in the database), I need to write a bunch of boilerplate. This is the macro that I have now:
use rusqlite::types::{FromSql, FromSqlResult, ToSql, ToSqlOutput, ValueRef};
macro_rules! make_id_type {
( $name:ident ) => {
///A type-safe primary key.
#[derive(Default, Clone, Copy, Hash, PartialEq, Eq, Deserialize, Serialize)]
pub struct $name(pub i64);
impl fmt::Display for $name {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
impl ToSql for $name {
fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
self.0.to_sql()
}
}
impl FromSql for $name {
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
Ok($name(i64::column_result(value)?))
}
}
};
}
make_id_type!(DocumentID);
make_id_type!(UserID);
//... and so on ...
This is pretty much the most basic usecase for macros. You can do some more interesting stuff than just take a name and insert it into some template, because macros can actually pattern-match the phrases given to them in the macro invocation. A good example, also from the RDBMS domain, would be https://docs.diesel.rs/diesel/macro.table.html https://docs.diesel.rs/diesel/macro.table.html (link goes to the documentation of the macro).