In javascript we can use the static keyword to define a static method or property for a class. Neither static methods nor static properties can be called on instances of the class. Instead, they're called on the class itself. So, for instance, we could count the number of instances of a certain class we've created:
class Player{
static playerCount = 0;
constructor(){
Player.playerCount ++;
}
}
Is their anything in rust that would roughly equivalent to this? Or possibly a library/macro that allows for something similar?
struct Player{}
impl Player{
static playerCount;
pub fn new()->Self{
playerCount ++
//increment playerCount
}
}
There isn't such a thing as a static field in a Rust struct. Rust's structs are closer to their C namesake than the classes you'd find in object-oriented languages.
The rough equivalent is probably a static mut variable, which requires the use of unsafe code. This is because a globally accessible, mutable value is going to be a source of undefined behavior (such as data races) and Rust wants all code to be free of UB unless you write the word unsafe.
For your use case, perhaps a PlayerManager struct which holds this state and is passed by &mut reference to the new function is a good idea.
struct PlayerManager {
count: usize,
}
impl PlayerManager {
pub fn add_player(&mut self) {
self.count += 1;
}
}
// then...
impl Player {
pub fn new(manager: &mut PlayerManager) -> Self {
manager.add_player();
// TODO: the rest of player construction
}
}
Related
I am a C++ programmer learning Rust, and one of my main use cases is a graph-based computation engine. In my graph I have store a homogeneous type, and then I derive from this with a more specific type e.g. in C++
class BaseNode {
public:
BaseNode(std::vector<std::shared_ptr<BaseNode>>& parents);
virtual ~BaseNode() = default;
virtual void update();
const std::vector<std::shared_ptr<BaseNode>>& parents() const;
...
};
template<typename T>
class TypedNode<T> : public BaseNode {
public:
const T& value() const { return value_; }
...
private:
T value_;
}
The idea is that the graph is traversed and update() is called on each node. The node knows what each of its parents "true type" is and so in its update() can do something like static_cast<TypedNode<DataBlob>>(parents()[0]).
How do I achieve something like this in Rust?
I thought about having a design like this:
trait BaseNode {
fn parents(&self) -> &Vec<dyn BaseNode>;
}
trait TypedNode<T>: BaseNode {
fn value(&self) -> &T;
}
But I read that I won't be able to cast the "trait object" from a BaseNode into a TypedNode<T>. (Or can I do it somehow using unsafe?). The other alternative I thought would be to have a struct that stores the data in Any and then to cast that, but does that incur some runtime cost?
If all node's parents have the same type then you can use that approach:
trait BaseNode {
type Parent: BaseNode;
fn parents(&self) -> &[Self::Parent];
}
trait TypedNode<P: BaseNode>: BaseNode<Parent = P> {
type ValueType;
fn value(&self) -> &Self::ValueType;
}
Rust playground
I'm not sure if I understand your question. Please let me know if it doesn't work for you.
When writing callbacks for generic interfaces, it can be useful for them to define their own local data which they are responsible for creating and accessing.
In C I would just use a void pointer, C-like example:
struct SomeTool {
int type;
void *custom_data;
};
void invoke(SomeTool *tool) {
StructOnlyForThisTool *data = malloc(sizeof(*data));
/* ... fill in the data ... */
tool.custom_data = custom_data;
}
void execute(SomeTool *tool) {
StructOnlyForThisTool *data = tool.custom_data;
if (data.foo_bar) { /* do something */ }
}
When writing something similar in Rust, replacing void * with Option<Box<Any>>, however I'm finding that accessing the data is unreasonably verbose, eg:
struct SomeTool {
type: i32,
custom_data: Option<Box<Any>>,
};
fn invoke(tool: &mut SomeTool) {
let data = StructOnlyForThisTool { /* my custom data */ }
/* ... fill in the data ... */
tool.custom_data = Some(Box::new(custom_data));
}
fn execute(tool: &mut SomeTool) {
let data = tool.custom_data.as_ref().unwrap().downcast_ref::<StructOnlyForThisTool>().unwrap();
if data.foo_bar { /* do something */ }
}
There is one line here which I'd like to be able to write in a more compact way:
tool.custom_data.as_ref().unwrap().downcast_ref::<StructOnlyForThisTool>().unwrap()
tool.custom_data.as_ref().unwrap().downcast_mut::<StructOnlyForThisTool>().unwrap()
While each method makes sense on its own, in practice it's not something I'd want to write throughout a code-base, and not something I'm going to want to type out often or remember easily.
By convention, the uses of unwrap here aren't dangerous because:
While only some tools define custom data, the ones that do always define it.
When the data is set, by convention the tool only ever sets its own data. So there is no chance of having the wrong data.
Any time these conventions aren't followed, its a bug and should panic.
Given these conventions, and assuming accessing custom-data from a tool is something that's done often - what would be a good way to simplify this expression?
Some possible options:
Remove the Option, just use Box<Any> with Box::new(()) representing None so access can be simplified a little.
Use a macro or function to hide verbosity - passing in the Option<Box<Any>>: will work of course, but prefer not - would use as a last resort.
Add a trait to Option<Box<Any>> which exposes a method such as tool.custom_data.unwrap_box::<StructOnlyForThisTool>() with matching unwrap_box_mut.
Update 1): since asking this question a point I didn't include seems relevant.
There may be multiple callback functions like execute which must all be able to access the custom_data. At the time I didn't think this was important to point out.
Update 2): Wrapping this in a function which takes tool isn't practical, since the borrow checker then prevents further access to members of tool until the cast variable goes out of scope, I found the only reliable way to do this was to write a macro.
If the implementation really only has a single method with a name like execute, that is a strong indication to consider using a closure to capture the implementation data. SomeTool can incorporate an arbitrary callable in a type-erased manner using a boxed FnMut, as shown in this answer. execute() then boils down to invoking the closure stored in the struct field implementation closure using (self.impl_)(). For a more general approach, that will also work when you have more methods on the implementation, read on.
An idiomatic and type-safe equivalent of the type+dataptr C pattern is to store the implementation type and pointer to data together as a trait object. The SomeTool struct can contain a single field, a boxed SomeToolImpl trait object, where the trait specifies tool-specific methods such as execute. This has the following characteristics:
You no longer need an explicit type field because the run-time type information is incorporated in the trait object.
Each tool's implementation of the trait methods can access its own data in a type-safe manner without casts or unwraps. This is because the trait object's vtable automatically invokes the correct function for the correct trait implementation, and it is a compile-time error to try to invoke a different one.
The "fat pointer" representation of the trait object has the same performance characteristics as the type+dataptr pair - for example, the size of SomeTool will be two pointers, and accessing the implementation data will still involve a single pointer dereference.
Here is an example implementation:
struct SomeTool {
impl_: Box<SomeToolImpl>,
}
impl SomeTool {
fn execute(&mut self) {
self.impl_.execute();
}
}
trait SomeToolImpl {
fn execute(&mut self);
}
struct SpecificTool1 {
foo_bar: bool
}
impl SpecificTool1 {
pub fn new(foo_bar: bool) -> SomeTool {
let my_data = SpecificTool1 { foo_bar: foo_bar };
SomeTool { impl_: Box::new(my_data) }
}
}
impl SomeToolImpl for SpecificTool1 {
fn execute(&mut self) {
println!("I am {}", self.foo_bar);
}
}
struct SpecificTool2 {
num: u64
}
impl SpecificTool2 {
pub fn new(num: u64) -> SomeTool {
let my_data = SpecificTool2 { num: num };
SomeTool { impl_: Box::new(my_data) }
}
}
impl SomeToolImpl for SpecificTool2 {
fn execute(&mut self) {
println!("I am {}", self.num);
}
}
pub fn main() {
let mut tool1: SomeTool = SpecificTool1::new(true);
let mut tool2: SomeTool = SpecificTool2::new(42);
tool1.execute();
tool2.execute();
}
Note that, in this design, it doesn't make sense to make implementation an Option because we always associate the tool type with the implementation. While it is perfectly valid to have an implementation without data, it must always have a type associated with it.
I'm coming from mostly OOP languages, so getting this concept to work in Rust kinda seems hard. I want to implement a basic counter that keeps count of how many "instances" I've made of that type, and keep them in a vector for later use.
I've tried many different things, first was making a static vector variable, but that cant be done due to it not allowing static stuff that have destructors.
This was my first try:
struct Entity {
name: String,
}
struct EntityCounter {
count: i64,
}
impl Entity {
pub fn init() {
let counter = EntityCounter { count: 0 };
}
pub fn new(name: String) {
println!("Entity named {} was made.", name);
counter += 1; // counter variable unaccessable (is there a way to make it global to the struct (?..idek))
}
}
fn main() {
Entity::init();
Entity::new("Hello".to_string());
}
Second:
struct Entity {
name: String,
counter: i32,
}
impl Entity {
pub fn new(self) {
println!("Entity named {} was made.", self.name);
self.counter = self.counter + 1;
}
}
fn main() {
Entity::new(Entity { name: "Test".to_string() });
}
None of those work, I was just trying out some concepts on how I could be able to implement such a feature.
Your problems appear to be somewhat more fundamental than what you describe. You're kind of throwing code at the wall to see what sticks, and that's simply not going to get you anywhere. I'd recommend reading the Rust Book completely before continuing. If you don't understand something in it, ask about it. As it stands, you're demonstrating you don't understand variable scoping, return types, how instance construction works, how statics work, and how parameters are passed. That's a really shaky base to try and build any understanding on.
In this particular case, you're asking for something that's deliberately not straightforward. You say you want a counter and a vector of instances. The counter is simple enough, but a vector of instances? Rust doesn't allow easy sharing like other languages, so how you go about doing that depends heavily on what it is you're actually intending to use this for.
What follows is a very rough guess at something that's maybe vaguely similar to what you want.
/*!
Because we need the `lazy_static` crate, you need to add the following to your
`Cargo.toml` file:
```cargo
[dependencies]
lazy_static = "0.2.1"
```
*/
#[macro_use] extern crate lazy_static;
mod entity {
use std::sync::{Arc, Weak, Mutex};
use std::sync::atomic;
pub struct Entity {
pub name: String,
}
impl Entity {
pub fn new(name: String) -> Arc<Self> {
println!("Entity named {} was made.", name);
let ent = Arc::new(Entity {
name: name,
});
bump_counter();
remember_instance(ent.clone());
ent
}
}
/*
The counter is simple enough, though I'm not clear on *why* you even want
it in the first place. You don't appear to be using it for anything...
*/
static COUNTER: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT;
fn bump_counter() {
// Add one using the most conservative ordering.
COUNTER.fetch_add(1, atomic::Ordering::SeqCst);
}
pub fn get_counter() -> usize {
COUNTER.load(atomic::Ordering::SeqCst)
}
/*
There are *multiple* ways of doing this part, and you simply haven't given
enough information on what it is you're trying to do. This is, at best,
a *very* rough guess.
`Mutex` lets us safely mutate the vector from any thread, and `Weak`
prevents `INSTANCES` from keeping every instance alive *forever*. I mean,
maybe you *want* that, but you didn't specify.
Note that I haven't written a "cleanup" function here to remove dead weak
references.
*/
lazy_static! {
static ref INSTANCES: Mutex<Vec<Weak<Entity>>> = Mutex::new(vec![]);
}
fn remember_instance(entity: Arc<Entity>) {
// Downgrade to a weak reference. Type constraint is just for clarity.
let entity: Weak<Entity> = Arc::downgrade(&entity);
INSTANCES
// Lock mutex
.lock().expect("INSTANCES mutex was poisoned")
// Push entity
.push(entity);
}
pub fn get_instances() -> Vec<Arc<Entity>> {
/*
This is about as inefficient as I could write this, but again, without
knowing your access patterns, I can't really do any better.
*/
INSTANCES
// Lock mutex
.lock().expect("INSTANCES mutex was poisoned")
// Get a borrowing iterator from the Vec.
.iter()
/*
Convert each `&Weak<Entity>` into a fresh `Arc<Entity>`. If we
couldn't (because the weak ref is dead), just drop that element.
*/
.filter_map(|weak_entity| weak_entity.upgrade())
// Collect into a new `Vec`.
.collect()
}
}
fn main() {
use entity::Entity;
let e0 = Entity::new("Entity 0".to_string());
println!("e0: {}", e0.name);
{
let e1 = Entity::new("Entity 1".to_string());
println!("e1: {}", e1.name);
/*
`e1` is dropped here, which should cause the underlying `Entity` to
stop existing, since there are no other "strong" references to it.
*/
}
let e2 = Entity::new("Entity 2".to_string());
println!("e2: {}", e2.name);
println!("Counter: {}", entity::get_counter());
println!("Instances:");
for ent in entity::get_instances() {
println!("- {}", ent.name);
}
}
I am writing a wrapper/FFI for a C library that requires a global initialization call in the main thread as well as one for destruction.
Here is how I am currently handling it:
struct App;
impl App {
fn init() -> Self {
unsafe { ffi::InitializeMyCLib(); }
App
}
}
impl Drop for App {
fn drop(&mut self) {
unsafe { ffi::DestroyMyCLib(); }
}
}
which can be used like:
fn main() {
let _init_ = App::init();
// ...
}
This works fine, but it feels like a hack, tying these calls to the lifetime of an unnecessary struct. Having the destructor in a finally (Java) or at_exit (Ruby) block seems theoretically more appropriate.
Is there some more graceful way to do this in Rust?
EDIT
Would it be possible/safe to use this setup like so (using the lazy_static crate), instead of my second block above:
lazy_static! {
static ref APP: App = App::new();
}
Would this reference be guaranteed to be initialized before any other code and destroyed on exit? Is it bad practice to use lazy_static in a library?
This would also make it easier to facilitate access to the FFI through this one struct, since I wouldn't have to bother passing around the reference to the instantiated struct (called _init_ in my original example).
This would also make it safer in some ways, since I could make the App struct default constructor private.
I know of no way of enforcing that a method be called in the main thread beyond strongly-worded documentation. So, ignoring that requirement... :-)
Generally, I'd use std::sync::Once, which seems basically designed for this case:
A synchronization primitive which can be used to run a one-time global
initialization. Useful for one-time initialization for FFI or related
functionality. This type can only be constructed with the ONCE_INIT
value.
Note that there's no provision for any cleanup; many times you just have to leak whatever the library has done. Usually if a library has a dedicated cleanup path, it has also been structured to store all that initialized data in a type that is then passed into subsequent functions as some kind of context or environment. This would map nicely to Rust types.
Warning
Your current code is not as protective as you hope it is. Since your App is an empty struct, an end-user can construct it without calling your method:
let _init_ = App;
We will use a zero-sized argument to prevent this. See also What's the Rust idiom to define a field pointing to a C opaque pointer? for the proper way to construct opaque types for FFI.
Altogether, I'd use something like this:
use std::sync::Once;
mod ffi {
extern "C" {
pub fn InitializeMyCLib();
pub fn CoolMethod(arg: u8);
}
}
static C_LIB_INITIALIZED: Once = Once::new();
#[derive(Copy, Clone)]
struct TheLibrary(());
impl TheLibrary {
fn new() -> Self {
C_LIB_INITIALIZED.call_once(|| unsafe {
ffi::InitializeMyCLib();
});
TheLibrary(())
}
fn cool_method(&self, arg: u8) {
unsafe { ffi::CoolMethod(arg) }
}
}
fn main() {
let lib = TheLibrary::new();
lib.cool_method(42);
}
I did some digging around to see how other FFI libs handle this situation. Here is what I am currently using (similar to #Shepmaster's answer and based loosely on the initialization routine of curl-rust):
fn initialize() {
static INIT: Once = ONCE_INIT;
INIT.call_once(|| unsafe {
ffi::InitializeMyCLib();
assert_eq!(libc::atexit(cleanup), 0);
});
extern fn cleanup() {
unsafe { ffi::DestroyMyCLib(); }
}
}
I then call this function inside the public constructors for my public structs.
To learn the Rust language, I'm taking an old C++ library I had lying around and trying to convert it to Rust. It used a lot of C++11 closures and I'm having some difficulty getting the concepts to translate.
In C++ I had something like this:
// library.h
struct Event {
// just some data
};
class Object {
public:
// ...
std::function<void(Event&)>& makeFunc(std::string& s) {
return m_funcs[s];
}
// ...
private:
// ...
std::map<std::string, std::function<void(Event&)>> m_funcs;
// ...
};
// main.cpp using the library
int main()
{
Object foo;
foo.makeFunc("func1") = [&]{
// do stuff
};
return 0;
}
The part that I'm having trouble with is properly storing the functions in a Rust HashMap collection. I tried this:
struct Event;
struct Object {
m_funcs : HashMap<String, FnMut(&Event)>
}
impl Object {
// send f as another parameter rather than try and return borrow
// compiler was complaining
fn makeFunc(&mut self, s : &str,f: FnMut(&Event)) {
self.m_funcs.insert(String::from_str(s), f);
}
}
but it says the trait core::marker::Sized is not implemented for the type 'for('r) core::ops::FnMut(&'r CreateEvent)'
This makes sense because FnMut is a trait, and therefore has no known size for the HashMap to make at compile time. So I figure that the hashmap would require an actual pointer rather than an abstract type. So I change it to this
struct Object {
m_funcs : HashMap<String, Box<FnMut(&Event)>>
}
impl Object {
fn makeFunc(&mut self, s : &str, f: &FnMut(&Event)) {
self.m_funcs.insert(String::from_str(s), Box::new(f));
}
}
now it says the trait 'for('r) core::ops::Fn<(&'r CreateEvent,)>' is not implemented for the type '&for('r) core::ops::FnMut(&'r CreateEvent)' [E0277] at the insert. This error makes no sense to me at all. Can someone explain to me the proper way to store a reference to a non-escaping closure in a HashMap?
You have taken a &FnMut(&Event)—a trait object—and, after boxing it, wish to store it as a Box<FnMut(&Event)>. Thus, you require that &FnMut(&Event) must implement FnMut(&Event), which it does not (and clearly cannot, for FnMut.call_mut takes &mut self).
What you wanted was to take an arbitrary type that implements FnMut(&Event)—that is, use generics—and take it by value. The signature is thus this:
fn make_func<F: FnMut(&Event)>(&mut self, s: &str, f: F)
It gets a little more complex than this due to lifetimes, however, but what you wish to do with regards to that may vary; Storing an unboxed closure with a reference arg in a HashMap has more information on that topic. Here’s what I believe you’re most likely to want:
struct Object<'a> {
m_funcs: HashMap<String, Box<FnMut(&Event) + 'a>>,
}
impl<'a> Object<'a> {
fn make_func<F: FnMut(&Event) + 'a>(&mut self, s: &str, f: F) {
self.m_funcs.insert(String::from_str(s), Box::new(f));
}
}
You could remove all the 'a in favour of just a single + 'static bound on F if you are happy to not let any of the closures capture references to their environments.