Derive Macro tokio_postgres_extractor::Columns
source · #[derive(Columns)]
{
// Attributes available to this derive:
#[column]
}
Expand description
Proc macro for deriving the Columns
trait.
Custom column names
If the column name is different from the name of the field, you can use
#[column(name = "Type")]`
ty: i32,
to explicitly specify a name. The name must be a string literal.
Explicit indices
If you already know the index a field maps to, you can use
#[column(idx = 123)]`
ty: i32,
to specify it.
Implementation
The critical section in the expansion of
#[derive(Columns)]
struct Account {
account_id: i32,
account_name: String,
account_role: i64,
}
is
for column in row.columns().iter() {
let name = column.name();
let idx = match name.len() {
10 => match name {
"account_id" => 0,
_ => continue,
},
12 => {
let b = name.as_bytes();
let disc = b[8];
match disc {
110 => match name {
"account_name" => 1,
_ => continue,
},
114 => match name {
"account_role" => 2,
_ => continue,
},
_ => continue,
}
}
_ => continue,
};
// ...
}
meaning that for each column the code
- uses a jump table indexed with the length of the column name,
- extracts an integer of size 1, 2, 4, or 8 from the column name,
- compares this integer to a number of candidates,
- compares the column name to the candidate.
This is very fast on current hardware. If the name of the candidate is no more than 16
bytes, then the final comparison will compile to a number of assembly instructions on
x86_64. Otherwise it compiles to a call to bcmp
. If you compile with -C target-cpu=native
, then even these calls to bcmp
will be inlined.
In practice, this means that the implementation of Columns
is usually O(N)
in the
number of columns with a “small” constant. In some degenerate cases the construction
above is not possible and the implementation will have to perform multiple string
comparisons. Even this is still much faster than using the phf crate or similar.