Implementing the Context Trait for Custom Structs
A more advanced guide for when you want to use your own structs as a source for variables.
So far, we’ve used environment variables and HashMap. But what if your data is
in a custom struct? You could convert it to a HashMap first, but that’s extra
work and a bit messy.
A better way is to teach envfmt how to read from your struct directly. You can
do this by implementing the Context trait. This is the key to making envfmt
super flexible.
The Context Trait
The trait itself is really simple. It looks like this:
pub trait Context {
fn get(&self, key: &str) -> Option<String>;
}It only has one method, get. This method takes a variable name (like
"RPC_URL") and should return Some(String) if the variable exists, or None
if it doesn’t.
Example: A Custom Ethereum Config Struct
Let’s say you have a config struct for your Ethereum application that you load from a file.
struct Config {
network: String,
chain_id: u64,
api_key: String,
}We want to use an instance of Config directly with format_with(). To do
that, we need to implement Context for it.
use envfmt::Context;
struct Config {
network: String,
chain_id: u64,
api_key: String,
}
// Here's the implementation
impl Context for Config {
fn get(&self, key: &str) -> Option<String> {
match key {
"NETWORK" => Some(self.network.clone()),
"CHAIN_ID" => Some(self.chain_id.to_string()),
"API_KEY" => Some(self.api_key.clone()),
_ => None, // For any other key, we don't have a value
}
}
}In the get method, we just use a match statement. If the key is one we
know, we return its value wrapped in Some(). Notice that we have to convert
the chain_id number to a String. If the key is unknown, we return None.
Putting It All Together
Now we can use our Config struct with format_with() just like we did with a
HashMap.
fn main() {
let config = Config {
network: "mainnet".to_string(),
chain_id: 1,
api_key: "my-secret-key".to_string(),
};
let template = "https://eth-${NETWORK}.g.alchemy.com/v2/$API_KEY (Chain ID: $CHAIN_ID)";
let rpc_url = format_with(template, &config).unwrap();
println!("{}", rpc_url);
}When you run this, the output will be:
https://eth-mainnet.g.alchemy.com/v2/my-secret-key (Chain ID: 1)And that’s it. By implementing one small trait, you can make envfmt work with
any of your own data structures.