Comments (4)
Does calling the macro from two different functions create two different objects? #3
Yes.
Am I misunderstanding something?
Yes, although I don't blame you. The docs could be more clear. Each occurrence of the get_or_init!
macro causes a new static map to be initialised. I.e. a separate use of get_or_init!
macro would refer to a separate singleton.
If so, how would I have to approach this, if I wanted such a generic "registry"-like singleton?
You need to factor the access into a single function. Something like:
use generic_singleton::get_or_init;
use std::collections::HashMap;
use std::fmt::Display;
use std::hash::Hash;
use std::sync::RwLock;
fn use_my_generic_singleton<T, U>(mut f: impl FnMut(&RwLock<HashMap<T, T>>) -> U) -> U
where
T: Eq + Copy + Display + Hash + Send + Sync + 'static,
{
let my_generic_singleton = get_or_init!(|| RwLock::new(HashMap::<T, T>::new()));
f(my_generic_singleton)
}
fn add_to_registry<T>(key: T, value: T) -> bool
where
T: Eq + Copy + Display + Hash + Send + Sync + 'static,
{
use_my_generic_singleton(|registry| {
if registry.read().unwrap().contains_key(&key) {
false
} else {
registry.write().unwrap().insert(key, value);
true
}
})
}
fn get_from_registry<T>(key: T) -> T
where
T: Eq + Copy + Display + Hash + Send + Sync + 'static,
{
use_my_generic_singleton(|registry| {
if !registry.read().unwrap().contains_key(&key) {
panic!("No such key registered: {}", key)
}
*registry.read().unwrap().get(&key).unwrap()
})
}
fn main() {
assert!(add_to_registry::<u32>(1, 10));
assert!(!add_to_registry::<u32>(1, 20));
let val = get_from_registry::<u32>(1);
assert_eq!(val, 10);
}
Although the above seems awfully complicated and I've not even convinced myself it makes sense. Will think about it some more but there's at least something for you for now.
I think I should probably update the docs or add a convenience method or perhaps both...
from generic_singleton.
@WalterSmuts Thanks a lot for the clarification and your example workaround.
Your suggestion of using a closure would probably be the most flexible in this scenario. I suppose, if all I want is the add/get functionality, I could also go the opposite route and put that logic in a single not-so-nice non-public function and have two friendly public interfaces for it like so: (Thinking about this in the context of library code.)
use std::collections::HashMap;
use std::fmt::Display;
use std::hash::Hash;
use std::sync::RwLock;
use generic_singleton::get_or_init;
trait MyItem: Eq + Copy + Display + Hash + Send + Sync + 'static {}
impl<T> MyItem for T
where
T: Eq + Copy + Display + Hash + Send + Sync + 'static
{}
fn use_registry<T: MyItem>(key: T, value: Option<T>) -> T {
let registry = get_or_init!(|| RwLock::new(HashMap::<T, T>::new()));
match value {
None => {
if !registry.read().unwrap().contains_key(&key) {
panic!("No such key registered: {}", key)
}
*registry.read().unwrap().get(&key).unwrap()
}
Some(value) => {
if registry.read().unwrap().contains_key(&key) {
panic!("Key already registered: {}", key)
}
registry.write().unwrap().insert(key, value);
value
}
}
}
pub fn add_to_registry<T: MyItem>(key: T, value: T) -> T {
use_registry(key, Some(value))
}
pub fn get_from_registry<T: MyItem>(key: T) -> T {
use_registry(key, None)
}
fn main() {
assert_eq!(add_to_registry::<u32>(1, 10), 10);
assert_eq!(get_from_registry::<u32>(1), 10);
}
This also runs as expected.
I still wonder, if it is possible to somehow achieve something like what I expected in the first place. I am very inexperienced with Rust still. And I have not looked deeper into your code yet, so I don't know if this could be added in as an additional feature or something, i.e. being able to "share" that singleton across functions.
But maybe you can dismiss this idea right off the bat, if you know it isn't possible. Maybe I'll gain some more insight, after going through your code.
Either way, this crate is cool and useful to me as is.
from generic_singleton.
I still wonder, if it is possible to somehow achieve something like what I expected in the first place.
It is but it'll probably lead to unwanted outcomes... It was like that in version 1.3 but had to add the following documentation:
DO NOT USE WITH A TYPE YOUR CRATE DOES NOT PRIVATELY OWN!!! The map is shared across crates, so if you use a type that is publicly available, then another crate will be able to mutate your singleton, breaking whichever rules you’ve got in place and vice-versa. Use the new type pattern if you need to use a public struct in the map.
It's a bit of a foot-gun for users where the workaround is just creating your own wrapping function (This is probably what you wanted BTW; ignore the other example):
use std::collections::HashMap;
use std::fmt::Display;
use std::hash::Hash;
use std::sync::RwLock;
use generic_singleton::get_or_init;
fn get_my_generic_singleton<T>() -> &'static RwLock<HashMap<T, T>>
where
T: Eq + Copy + Display + Hash + Send + Sync + 'static,
{
get_or_init!(|| RwLock::new(HashMap::<T, T>::new()))
}
fn add_to_registry<T>(key: T, value: T) -> bool
where
T: Eq + Copy + Display + Hash + Send + Sync + 'static,
{
let registry = get_my_generic_singleton();
if registry.read().unwrap().contains_key(&key) {
false
} else {
registry.write().unwrap().insert(key, value);
true
}
}
fn get_from_registry<T>(key: T) -> T
where
T: Eq + Copy + Display + Hash + Send + Sync + 'static,
{
let registry = get_my_generic_singleton();
if !registry.read().unwrap().contains_key(&key) {
panic!("No such key registered: {}", key)
}
*registry.read().unwrap().get(&key).unwrap()
}
fn main() {
assert!(add_to_registry::<u32>(1, 10));
assert!(!add_to_registry::<u32>(1, 20));
let val = get_from_registry::<u32>(1);
assert_eq!(val, 10);
}
from generic_singleton.
@WalterSmuts Ah, of course, just grabbing the singleton from a separate function makes much more sense. Thank you.
Interesting side note about the 🦶 🔫 with public types. Good to know that this is no longer an issue.
from generic_singleton.
Related Issues (2)
- Data Race Unsoundness HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from generic_singleton.