pablomansanet / tightness Goto Github PK
View Code? Open in Web Editor NEWLicense: MIT License
License: MIT License
Hi! I've read your post and think that this is a pretty cool idea. But I also think that there are some things that could be better. For example, when I tried to use this lib in my project, I found myself doing something like this:
use tightness::bound;
pub struct User {
pub name: UserName,
}
bound!(UserName: String where |s| !s.is_empty());
impl User {
fn new(name: &str) -> Result<User, &'static str> {
let name = name.trim().to_string(); // no need to make programmer always trim the string himself
let name = UserName::new(name).map_err(|_e| "name is empty")?;
Ok(User { name })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
assert!(matches!(User::new(" "), Err("name is empty")));
assert!(matches!(User::new(" something "), Ok(_)));
}
}
There's two problems:
.map_err
everywhere.All of this things tear the domain logic of the type into different places, which is not good. The code above solves some of this problems, but still if I want to mutate the name
somewhere else, I need to convert the error there. And, of course, the same thing applies to manual struct creation.
How do you thing, is it possible to expand the macro so it allows user to mutate the value and return another error? Would be happy to help with that, although I have no experience writing macros.
And one side note: is it possible to somehow integrate this thing with serde
if internal type implements Serialize
and Deserialize
? I would be awesome if the validation could be handled during serialization.
The protecting code of mutators does not protect the (implicit) panic exit point with assertions of the invariant holding. This makes it possible to observe an instace of a tightness-defined type whose invariant is in fact violated.
bound!(Letter: char where |c| c.is_alphabetic());
struct Observer(Letter);
impl Drop for Observer {
fn drop(&mut self) {
if !self.0.is_alphabetic() {
println!("Woah there");
}
}
}
let mut obs = Observer(Letter::new('a').unwrap());
obs.0.mutate(|l| *l = '0'); // Not, in fact, alphabetic
// Prints: Woah there
However, for usual validity invariants such as those upheld by str
or NonZeroU8
etc. even this kind of observation is forbidden. This may be a concious design decision as the only 'correct' way to handle this would be an immediate program abort instead of a usual panic. For the fallback mutate_or
it is at least theoretically possible to handle it correctly while continuing to panic but you need to assign to self
through a drop-guard instead of a code path that is never reached on panic unwinding.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.