Sealing with Enums
#![allow(unused)] fn main() { use std::collections::BTreeMap; pub enum GetSource { WebUrl(String), BytesMap(BTreeMap<String, Vec<u8>>), } impl GetSource { fn get(&self, url: &str) -> Option<&Vec<u8>> { match self { Self::WebUrl(source) => unimplemented!(), Self::BytesMap(map) => map.get(url), } } } }
-
Motivation: API is designed around a specific list of types that are valid for it, users of the API are not expected to extend it.
-
Enums in Rust are algebraic data types, we can define different structures for each variant.
For some domains, this might be enough polymorphism for the problem. Experiment and see what works, what solutions seem to make more sense.
-
By having the user-facing part of the API refer to an enum, users know what types are valid inputs and can construct those types using the available methods to do so.
-
If the types that make up the enum have invariants that the API internally upholds, and the only way users can construct those types is through constructors that build and maintain those invariants, then you can be sure that inputs to a generic method uphold their invariants.
-
If the types that make up the enum instead are types the user can freely construct, then sanitisation and interpretation may need to be taken into consideration.
-