News for hackers. Stuff that matters.
Re:Rust 1.43 by majewsky on Thursday April 23, 2020 @04:05PM (#22960564)
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 (link goes to the documentation of the macro).

There are no comments on this comment yet.