Store immutable instances of Rust struct, but where? [duplicate] - rust

This question already has answers here:
How can you make a safe static singleton in Rust?
(3 answers)
How do I create a global, mutable singleton?
(7 answers)
Closed 4 years ago.
Sometimes, it’s handy to have a few instances of a struct stored and accessible everywhere.
For instance, if I want to store some meta-data about a currency in a struct like this:
struct Currency {
name: &'static str,
iso_symbols: Vec<&'static str>
}
I would then create an instance of Currency for every major currency. As these property don’t change, it could be hard-coded, at least for some currencies.
I tried to use const, which would work without a Vec (the vec! macro does an allocation, which is not allowed in const).
const BTC: Currency = Currency {
name: "Bitcoin",
iso_symbols: vec!["BTC", "XBT"]
};
So what workaround would you suggest to store a bunch of instance of Currency (for EUR, USD, BTC…)?
Here, in the Rust Playground.
EDIT: My question is quite similar to this one. The only difference is that I don’t need a mutable singleton, so the “Non-answer answer” doesn’t apply, right? The lazy_static idea is great though!
It might be interesting to keep this question around since I didn’t searched with the keyword singleton and I may not be alone to miss this way to consider the problem.

As pointed out in the comments, the lazy_static crate works well.
pub struct Currency {
name: &'static str,
iso_symbols: Vec<&'static str>,
}
lazy_static! {
pub static ref BTC: Currency = Currency {
name: "Bitcoin",
iso_symbols: vec!["BTC", "XBT"]
};
}
fn main() {
println!("{} {:?}", BTC.name, BTC.iso_symbols);
}
We have this global (with pub) variable BTC I was looking for.

Related

Only setting one field in a Rust `Default` implementation [duplicate]

This question already has answers here:
Is there a short way to implement Default for a struct that has a field that does not implement Default?
(3 answers)
Closed 1 year ago.
I have a Rust struct with a large number of fields, all of which are themselves Default. I'd like to create a custom impl Default for it, with the following semantics:
One of the fields has a custom value
All other fields get their value from their Default::default
Here's how I hoped to do that:
impl Default for Foo {
fn default() -> Self {
Self {
thing: 2,
..Default::default()
}
}
}
...but that actually causes unchecked recursion, since ..Default::default() calls Self::default() rather than $member::default() for each member of Self.
Is there any way to accomplish this, short of writing a custom macro or explicitly listing every field?
You can use the derivative crate to achieve this. It provides alternative versions of some of the standard library derive macros with additional customizability:
#[derive(Debug, Derivative)]
#[derivative(Default)]
struct Foo {
foo: u8,
#[derivative(Default(value="2"))]
thing: u8,
}
Just using the standard library, you can either derive Default to get the default values for all fields, or implement it completely manually.

Constructing and returning a struct with custom &str members [duplicate]

This question already has answers here:
Return local String as a slice (&str)
(7 answers)
Proper way to return a new string in Rust
(2 answers)
Is there any way to return a reference to a variable created in a function?
(5 answers)
Why can't I store a value and a reference to that value in the same struct?
(4 answers)
Closed 2 years ago.
I'm working with an external type (i.e., not my code), that has a bunch of &str members:
#[derive(Default, Clone)]
pub struct SomeExternalThingie<'a> {
pub name: &'a str,
pub description: Option<&'a str>,
pub author: Option<&'a str>,
}
I want to make my own function which constructs and returns one of these things. I want to dynamically construct some of the strings used as members:
fn my_func_to_make_a_thingie<'a>(name: &'a str) -> MyThingie<'a> {
let mydesc = format!("Hi, I'm your friendly neighborhood {}!",
name);
SomeExternalThingie {
name: name,
description: Some(mydesc.as_str()),
..Default::default()
}
}
Of course, this won't compile, because the lifetime of mydesc ends when the function does. What's the best practice for dealing with a situation like this? I'm obviously new to Rust, but it seems like this will be a common scenario.
My only thought to change the return type to return both the desired structure and the storage for the string(s)... either by returning a tuple, or making a custom struct. This feels awkward, though, and I was wondering if there was a better way, or at least a convention of sorts.
For some context - the actual use case that prompted this was that I wanted to return a clap::App object. I wanted to do this mostly for organizational reasons - I know that in this case I can just include it in my main function, without the sub-function (even though it makes it longer than I'd like), and I'll probably end up doing this. However, this seems like a common pattern, and I wanted to learn the "Rust way" to deal with this.

How do I access struct fields within default method definitions of traits? [duplicate]

This question already has answers here:
Is it possible to access struct fields from within a trait?
(3 answers)
Implementing a trait for multiple types at once
(4 answers)
Closed 3 years ago.
I see some related questions (like this and this) but I'm hoping that my use case for default methods is unique enough to ask a slightly different question. The following minimal example works and outputs "Sheriff Ted" shot "Billy the Kid"!:
#[derive(Debug)]
struct Actor {
name: String,
}
fn main() {
let cop = Actor {
name: String::from("Sheriff Ted"),
};
let robber = Actor {
name: String::from("Billy the Kid")
};
println!("{:?} shot {:?}!", cop.name, robber.name); // without the trait. with:
// cop.shoot(&robber);
}
//pub trait Shoot {
// fn shoot(&self, other: &Actor) {
// println!("\n{:?} shot {:?}!",
// &self.name,
// &other.name,
// )
// }
//}
//
//impl Shoot for Actor {}
As you can see, I want impart the Shoot implementation and the shoot method it contains on the Actor struct. When I uncomment the Shoot trait, its implementation on Actor, and the call cop.shoot(&robber), I get the error message related questions have gotten, as well: error[E0609]: no field 'name' on type '&Self'.
My first thought was to specify &self: Actor in the default method's signature, but that yields the delimiter error, so isn't syntactically valid.
I think this question is unique because the other questions seem to misunderstand how the generics they specify are shadowing their intended types, and in my case I'm not understanding why I can't access fields within the structs on which I am trying to implement a default method.
This works for cases when only Actors need to shoot, but I am looking for a way to apply this behavior (right now, just printlning) across multiple types.
impl Actor {
fn shoot(&self, other: &Actor) {
println!("\n{:?} shot {:?}!",
self.name,
other.name,
)
}
}
You are not trying to implement a default method on any structs; you are implementing it for the trait. Therefore you can't access any fields on any structs; you can only access what the trait demands.
A default implementation of a trait methods means that any type that implements the non-defaulted methods of the trait can use the default method, no matter what it looks like otherwise. But you expect that the implementing type has a name field in addition to what the trait demands (it demands nothing, by the way).
This is simply not a valid assumption.
I wonder why you're using a trait here at all. If you are okay with requiring self to be Actor in the shoot method, why is it a method of a trait? Why isn't it an inherent method of the Actor struct without any traits?
After having read Sebastian's response, I think the "answer" is: you can't name struct fields in traits' default methods because you don't know what fields a struct may have until the implementation of the trait. So you'd define an (abstract?) method signature, and then make it concrete when it's implemented. In my case, this works:
trait Shoot {
fn shoot(&self, other: &Actor);
}
impl Shoot for Actor {
fn shoot(&self, other: &Actor) {
println!("\n{:?} shot {:?}!",
self.name,
other.name,
);
}
}
Still interested to know if I can constrain a trait to be applied only to structs with certain fields and if this is different than "trait bounds". (It is, I think...)

How to give Hashmap entries references to each other? [duplicate]

This question already has answers here:
Why can't I store a value and a reference to that value in the same struct?
(4 answers)
Implement graph-like data structure in Rust
(3 answers)
What is the right smart pointer to have multiple strong references and allow mutability?
(1 answer)
Mutating one field while iterating over another immutable field
(3 answers)
How can I borrow from a HashMap to read and write at the same time?
(2 answers)
Closed 3 years ago.
I am trying to implement the JVM in Rust as a fun project but I am struggling with an issue involving references. When classes are loaded from class files, their references to other classes are represented as Strings. After the loading phase, a JVM should link classes with actual references to each other. I cannot figure out how to do this with Rust's references. Here is a stripped down version of what I am trying to achieve. (an MCV example)
use ClassRef::{Symbolic, Static};
use std::collections::HashMap;
fn main() {
let mut loader = ClassLoader { classes: HashMap::new() };
loader.load_class("java/lang/String", "java/lang/Object");
// java.lang.Object is the only class without a direct superclass
loader.load_class("java/lang/Object", "");
loader.link_classes();
}
struct ClassLoader<'a> {
classes: HashMap<String, Class<'a>>
}
impl<'a> ClassLoader<'a> {
pub fn load_class(&mut self, name: &str, super_name: &str) {
self.classes.insert(name.to_owned(), Class::new(name, super_name));
}
pub fn link_classes(&mut self) {
// Issue 1: Editing the stored class requires a mutable borrow
for (name, class) in self.classes.iter_mut() {
// Issue 2: I am not allowed to move this value to itself
class.super_class = match class.super_class {
// Issue 3: Storing a reference to another value in the map
Symbolic(ref super_name) => Static(self.classes.get(super_name)),
a => a
}
}
}
}
struct Class<'a> {
super_class: ClassRef<'a>,
name: String
}
impl<'a> Class<'a> {
pub fn new(name: &str, super_name: &str) -> Self {
Class {
name: name.to_owned(),
super_class: Symbolic(super_name.to_owned())
}
}
}
enum ClassRef<'a> {
Symbolic(String),
Static(Option<&'a Class<'a>>)
}
Currently, there are three issues with the process that I am unable to solve.
First, when I iterate through the list of loaded classes, I need to be able to change the field Class#super_class, so I need a mutable iterator. This means that I have a mutable borrow on self.classes. I also need an immutable borrow on self.classes during the iteration to look up a reference to the superclass. The way I feel like this should be solved is having a way of proving to the compiler that I am not mutating the map itself, but only a key. I feel like it has to do with std::cell::Cell as shown in Choosing your Guarantees, but the examples seem so simple I don't know how to correlate it to what I am trying to do here.
Second, I need the previous value of Class#super_class in order to calculate the new one. Essentially, I am moving the previous value out, changing it, and then moving it back in. I feel like this could be solved with some sort of higher order Map function to work on the value in place, but once again I'm not sure.
Third, when I give one class a reference to another class, there is no way of proving to the compiler that the other class won't be removed from the hashmap, causing the reference to point to deallocated memory. When classes are loaded, one class name will always point to the same class and classes are never unloaded, so I know that the value will always be there. The way I think this should be solved is with a Hashmap implementation which doesn't allow values to be overwritten or removed. I tried to poke around for such a thing but I couldn't find it.
EDIT: Solution
The duplicates linked were certainly helpful, but I ended up not using reference counting pointers (Rc<>) because the relationships between classes can sometimes be cyclic, so trying to drop the ClassLoader would end up leaking memory. The solution I settled on is using an immutable reference to a
Typed-Arena allocator. This allocator is an insertion only allocator which ensures the references it distributes are valid for the entire life of the reference to the allocator, as long as said reference is immutable. I then used the hashmap to store the references. That way everything is dropped when I drop the ClassLoader. Hopefully anyone that trying to implement a relationship similar to this finds the following code helpful.
extern crate typed_arena;
use ClassRef::{Symbolic, Static};
use std::collections::HashMap;
use std::cell::RefCell;
use core::borrow::BorrowMut;
use typed_arena::Arena;
fn main() {
let mut loader = ClassLoader { class_map: HashMap::new(), classes: &Arena::new() };
loader.load_class("java/lang/String", "java/lang/Object");
// java.lang.Object is the only class without a direct superclass
loader.load_class("java/lang/Object", "");
loader.link_classes();
}
struct ClassLoader<'a> {
classes: &'a Arena<RefCell<Class<'a>>>,
class_map: HashMap<String, &'a RefCell<Class<'a>>>
}
impl<'a> ClassLoader<'a> {
pub fn load_class(&mut self, name: &str, super_name: &str) {
let super_opt = if super_name.len() > 0 {
Some(super_name)
} else {
None
};
let class = Class::new(name, super_opt);
let class_ref = self.classes.alloc(RefCell::new(class));
self.class_map.insert(name.to_owned(), class_ref);
}
pub fn link_classes(&mut self) {
for (_name, class_ref) in &self.class_map {
let mut class = (*class_ref).borrow_mut();
if let Some(Symbolic(super_name)) = &class.super_class {
let super_class = self.class_map.get(super_name);
let super_class = super_class.map(|c| Static(c.clone()));
*class.super_class.borrow_mut() = super_class;
}
}
}
}
struct Class<'a> {
super_class: Option<ClassRef<'a>>,
name: String
}
impl<'a> Class<'a> {
pub fn new(name: &str, super_name: Option<&str>) -> Self {
Class {
name: name.to_owned(),
super_class: super_name.map(|name| Symbolic(name.to_owned()))
}
}
}
enum ClassRef<'a> {
Symbolic(String),
Static(&'a RefCell<Class<'a>>)
}

Is there any way I can add custom functions to a predefined struct? [duplicate]

This question already has answers here:
Is there a way other than traits to add methods to a type I don't own?
(2 answers)
How can I add new methods to Iterator?
(1 answer)
Closed 4 years ago.
I have a struct that is used by different functions. Instead of passing the struct as input to the different functions, I think I can implement the struct with all the functions that need to access it. However, there are certain fixed basic functions that I want to provide so that whenever the struct is created, I don't have to implement the same set of functions over and over again.
Put in another way, what I really want is the struct inheritance: I have certain set of methods associated with struct and user can add their custom functions to struct and allow them to access the data contained in data. Is there anyway able to do so?
Concretely, suppose I have a struct called AppContext and the fixed set of functions are new and bdev_name:
pub struct AppContext {
bdev: *mut raw::spdk_bdev,
bdev_desc: *mut raw::spdk_bdev_desc,
bdev_io_channel: *mut raw::spdk_io_channel,
buff: *mut c_char,
bdev_name: *const c_char,
}
impl AppContext {
pub fn new() -> Self {
let context: AppContext;
unsafe {
context = mem::uninitialized();
}
context
}
pub fn bdev_name(&mut self, name: &str) {
self.bdev_name = CString::new(name)
.expect("Couldn't create a string")
.into_raw()
}
}
Now, when I use this struct, I do:
let mut context = AppContext::new();
context.bdev_name("Nvme0n1");
I want to add one extra function (say end()) that can work on the data within the context struct. However, end() is very domain specific function and needed in a specific module, and thus it's not a good idea to implement as part of the context struct.
Is there any way I can workaround the issue (i.e. add custom function to predefined struct)?

Resources