Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- mod without_phantom_types {
- /// struct without phantom types
- /// public_key may be absent, because the generating of the key pair
- /// may happen later, than the creation of the ports
- #[derive(Debug, Clone)]
- struct WireguardPort {
- id: i32,
- public_key: Option<String>,
- }
- impl WireguardPort {
- fn make(id: i32) -> Self { Self { id, public_key: None } }
- fn with_public_key(&self, public_key: &str) -> Self {
- WireguardPort { id: self.id, public_key: Some(public_key.to_string()) }
- }
- fn id(&self) -> i32 { self.id }
- fn public_key(&self) -> String {
- self.public_key.clone().unwrap() // might fail here!
- }
- }
- fn connect(port1: WireguardPort, port2: WireguardPort) {
- // do things like we're creating wireguard peer
- let _pubkey1 = port1.public_key();
- let _pubkey2 = port2.public_key();
- println!("Wireguard peer created, {} <-> {}", port1.id(), port2.id());
- }
- // the program compiles, but aborts at runtime
- pub fn test() {
- let port1 = WireguardPort::make(1);
- let port2 = WireguardPort::make(2);
- // let port1 = port1.with_public_key("pubkey1");
- // let port2 = port2.with_public_key("pubkey2");
- connect(port1, port2);
- }
- }
- mod with_phantom_types {
- use std::marker::PhantomData;
- /// struct with phantom types
- /// public_key may be absent, because the generating of the key pair
- /// may happen later, than the creation of the ports
- struct WireguardPort<T: PubkeyState> {
- id: i32,
- public_key: Option<String>,
- _pd: PhantomData<T>,
- }
- /// in Rust this is known as `Typestate pattern`
- trait PubkeyState {}
- struct NoPubkey;
- struct WithPubkey;
- impl PubkeyState for NoPubkey {}
- impl PubkeyState for WithPubkey {}
- impl<T: PubkeyState> WireguardPort<T> {
- fn id(&self) -> i32 { self.id }
- fn with_public_key(&self, public_key: &str) -> WireguardPort<WithPubkey> {
- WireguardPort { id: self.id, public_key: Some(public_key.to_string()), _pd: PhantomData }
- }
- }
- impl WireguardPort<NoPubkey> {
- fn make(id: i32) -> Self { Self { id, public_key: None, _pd: PhantomData } }
- }
- impl WireguardPort<WithPubkey> {
- fn public_key(&self) -> String { self.public_key.clone().expect("Impossible") }
- }
- fn connect(port1: WireguardPort<WithPubkey>, port2: WireguardPort<WithPubkey>) {
- // do things like we're creating wireguard peer
- let _pubkey1 = port1.public_key();
- let _pubkey2 = port2.public_key();
- println!("Wireguard peer created, {} <-> {}", port1.id(), port2.id());
- }
- pub fn test() {
- let port1 = WireguardPort::make(1);
- let port2 = WireguardPort::make(2);
- // Commenting code below does not compile as expected:
- // Type mismatch [E0308]
- // expected `WireguardPortExt<WithPubkey>`, but found `WireguardPortExt<NoPubkey>`
- let port1 = port1.with_public_key("pubkey1");
- let port2 = port2.with_public_key("pubkey2");
- connect(port1, port2);
- }
- }
- pub fn main() {
- without_phantom_types::test();
- with_phantom_types::test();
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement