How to use a struct without initializing its members? - rust

I'm trying to use a struct without initializing some of its members, to be able to use it:
struct Structure {
initialized: bool,
data: StructureData, // This is another struct...
target: TargetTrait, // This member that I don't need to initialize.
}
impl Structure {
pub fn initialize(&mut self) -> bool {
if self.initialized {
false
} else {
// Here I should initialize the target...
self.target = initializeTarget(...); // No problem...
self.initialized = true;
true
}
}
pub fn new(&self) -> Structure {
Structure {
initialized: false, // The initialize method will do that...
data: StructureData, // Initializing Structure data behind the
// scenes...
// Here the struct needs some value for the target, but I cannot provide any value,
// Because the initialization method will do that job...
target: None, // I tried using (None), and Option<T>,.
// But the TargetTrait refused.
}
}
}
// main function:
fn main() {
let structure: Structure = Structure::new(); // It should construct a new structure...
if structure.initialize() {
// Here, I should do some work with the target...
}
}
I tried to use Option, but the target trait doesn't implement Option, or even
#[derive(Default)]

This could be solved using the Typestate pattern, under the form of a builder type.
The basic idea behind this pattern is that invalid states shouldn't be representable at runtime (eg. by changing the value of the initialized field, in this case).
Instead this should be handled by the type system at compile time.
For example, here you'd use two distinct types.
A first "uninitialised" builder type that represents the state of the structure without the target present, and the initialized Structure containing the target. It does not contain an initialized field though, since by virtue of being built by the other class, it can only represent an initialized state (hence the Type State).
struct Structure {
data: StructureData,
target: TargetTrait,
}
struct StructureBuilder {
data: StructureData,
}
impl StructureBuilder {
pub fn initialize(self) -> Structure {
// Here I should initialize the target...
Structure {
data: self.structureData,
target: initializeTarget(),
}
}
pub fn new() -> StructureBuilder {
StructureBuilder {
data: StructureData, // Initializing Structure data behind the scenes
}
}
}
This type takes care of initializing the target with the initialize method.
However, the method signature (taking self by value) makes sure that the instance of StructureBuilder cannot be reused afterwards, and the newly created Structure takes ownership of the data being moved into it.
It would then be used like this:
fn main() {
let builder = StructureBuilder::new();
let structure = builder.initialize();
}

Related

How to create a derived column for my struct?

#[derive(Serialize, Deserialize, Debug)]
struct Product {
id: usize,
name: String,
timestamp: i128
}
I deserialize this struct value from a JSON value.
Now I want to expose another property on my struct:
dt: OffsetDateTime
I want this property to be immutable, and set only once. So I don't want to expose a function that like below b/c it would re-calculate each time I call it:
impl Product {
fn dt(&self) -> OffsetDateTime {
OffsetDateTime::from_unix_timestamp_nanos(self.timestamp)
}
}
In java world or other languages I would do something like this:
private dt: OffsetDateTime = null;
public OffsetDateTime getDt() {
if(dt == null) {
dt = OffsetDateTime::from_unix_timestamp_nanos(self.timestamp)
}
return dt;
}
Does Rust have a similar pattern I can use?
You have three options:
Initialize it when initializing the struct, by providing a constructor. This is by far the easiest solution, if initialization isn't expensive or access is common enough that initializing always is not a problem. This is not equivalent to your Java code, however.
Store an Option<OffsetDateTime> and use Option::get_or_insert_with() to initialize it on access. This is cheapier than the third option, but requires a &mut access:
pub fn dt(&mut self) -> &OffsetDateTime {
self.dt.get_or_insert_with(|| { /* Initialization logic */ })
}
Use a library such as once_cell (or the unstable versions in std) to initialize under & access. You can use either Sync or not, depending on whether you need multiple threads to access the data):
pub fn dt(&self) -> &OffsetDateTime {
self.dt.get_or_init(|| { /* Initialization logic */ })
}
You could use an Option to simulate the Java behavior.
struct P {
pub thing: Option<i32>
}
impl P {
pub fn calc_thing( mut self ) -> i32 {
if let None = self.thing {
self.thing = Some(5);
}
self.thing.unwrap()
}
}
fn main(){
let p = P{ thing: None };
println!( "{}", p.calc_thing() );
}

Rust: joining thread fails with: cannot move out of dereference of `std::sync::MutexGuard<'_, models::worker::Worker>`

I am having a hard time figuring out how to sort out this issue.
So I have a class ArcWorker holding a shared reference to Worker (as you can remark below).
I wrote a function in ArcWorker called join() in which the line self.internal.lock().unwrap().join(); fails with the following error:
cannot move out of dereference of std::sync::MutexGuard<'_, models::worker::Worker>
What I attempt through that line is to lock the mutex, unwrap and call the join() function from the Worker class.
As far as I understand, once that the lock function is called and it borrows a reference to self (&self), then I need some way to get to pass self by value to join (std::thread's join function requires passing self by value).
What can I do to make this work? Tried to find an answer to my question for hours but to no avail.
pub struct Worker {
accounts: Vec<Arc<Mutex<Account>>>,
thread_join_handle: Option<thread::JoinHandle<()>>
}
pub struct ArcWorker {
internal: Arc<Mutex<Worker>>
}
impl ArcWorker {
pub fn new(accounts: Vec<Arc<Mutex<Account>>>) -> ArcWorker {
return ArcWorker {
internal: Arc::new(Mutex::new(Worker {
accounts: accounts,
thread_join_handle: None
}))
}
}
pub fn spawn(&self) {
let local_self_1 = self.internal.clone();
self.internal.lock().unwrap().thread_join_handle = Some(thread::spawn(move || {
println!("Spawn worker");
local_self_1.lock().unwrap().perform_random_transactions();
}));
}
pub fn join(&self) {
self.internal.lock().unwrap().join();
}
}
impl Worker {
fn join(self) {
if let Some(thread_join_handle) = self.thread_join_handle {
thread_join_handle.join().expect("Couldn't join the associated threads.")
}
}
fn perform_random_transactions(&self) {
}
}
Since you already hold JoinHandle in an option, you can make Worker::join() take &mut self instead of self and change the if let condition to:
// note added `.take()`
if let Some(thread_join_handle) = self.thread_join_handle.take() {
Option::take() will move the handle out of the option and give you ownership over it, while leaving None in self.thread_join_handle. With this change ArcWorker::join() should compile as-is.

What is the Rust equivalent of C++'s shared_from_this?

I have an object that I know that is inside an Arc because all the instances are always Arced. I would like to be able to pass a cloned Arc of myself in a function call. The thing I am calling will call me back later on other threads.
In C++, there is a standard mixin called enable_shared_from_this. It enables me to do exactly this
class Bus : public std::enable_shared_from_this<Bus>
{
....
void SetupDevice(Device device,...)
{
device->Attach(shared_from_this());
}
}
If this object is not under shared_ptr management (the closest C++ has to Arc) then this will fail at run time.
I cannot find an equivalent.
EDIT:
Here is an example of why its needed. I have a timerqueue library. It allows a client to request an arbitrary closure to be run at some point in the future. The code is run on a dedicated thread. To use it you must pass a closure of the function you want to be executed later.
use std::time::{Duration, Instant};
use timerqueue::*;
use parking_lot::Mutex;
use std::sync::{Arc,Weak};
use std::ops::{DerefMut};
// inline me keeper cos not on github
pub struct MeKeeper<T> {
them: Mutex<Weak<T>>,
}
impl<T> MeKeeper<T> {
pub fn new() -> Self {
Self {
them: Mutex::new(Weak::new()),
}
}
pub fn save(&self, arc: &Arc<T>) {
*self.them.lock().deref_mut() = Arc::downgrade(arc);
}
pub fn get(&self) -> Arc<T> {
match self.them.lock().upgrade() {
Some(arc) => return arc,
None => unreachable!(),
}
}
}
// -----------------------------------
struct Test {
data:String,
me: MeKeeper<Self>,
}
impl Test {
pub fn new() -> Arc<Test>{
let arc = Arc::new(Self {
me: MeKeeper::new(),
data: "Yo".to_string()
});
arc.me.save(&arc);
arc
}
fn task(&self) {
println!("{}", self.data);
}
// in real use case the TQ and a ton of other status data is passed in the new call for Test
// to keep things simple here the 'container' passes tq as an arg
pub fn do_stuff(&self, tq: &TimerQueue) {
// stuff includes a async task that must be done in 1 second
//.....
let me = self.me.get().clone();
tq.queue(
Box::new(move || me.task()),
"x".to_string(),
Instant::now() + Duration::from_millis(1000),
);
}
}
fn main() {
// in real case (PDP11 emulator) there is a Bus class owning tons of objects thats
// alive for the whole duration
let tq = Arc::new(TimerQueue::new());
let test = Test::new();
test.do_stuff(&*tq);
// just to keep everything alive while we wait
let mut input = String::new();
std::io::stdin().read_line(&mut input).unwrap();
}
cargo toml
[package]
name = "tqclient"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
timerqueue = { git = "https://github.com/pm100/timerqueue.git" }
parking_lot = "0.11"
There is no way to go from a &self to the Arc that self is stored in. This is because:
Rust references have additional assumptions compared to C++ references that would make such a conversion undefined behavior.
Rust's implementation of Arc does not even expose the information necessary to determine whether self is stored in an Arc or not.
Luckily, there is an alternative approach. Instead of creating a &self to the value inside the Arc, and passing that to the method, pass the Arc directly to the method that needs to access it. You can do that like this:
use std::sync::Arc;
struct Shared {
field: String,
}
impl Shared {
fn print_field(self: Arc<Self>) {
let clone: Arc<Shared> = self.clone();
println!("{}", clone.field);
}
}
Then the print_field function can only be called on an Shared encapsulated in an Arc.
having found that I needed this three times in recent days I decided to stop trying to come up with other designs. Maybe poor data design as far as rust is concerned but I needed it.
Works by changing the new function of the types using it to return an Arc rather than a raw self. All my objects are arced anyway, before they were arced by the caller, now its forced.
mini util library called mekeeper
use parking_lot::Mutex;
use std::sync::{Arc,Weak};
use std::ops::{DerefMut};
pub struct MeKeeper<T> {
them: Mutex<Weak<T>>,
}
impl<T> MeKeeper<T> {
pub fn new() -> Self {
Self {
them: Mutex::new(Weak::new()),
}
}
pub fn save(&self, arc: &Arc<T>) {
*self.them.lock().deref_mut() = Arc::downgrade(arc);
}
pub fn get(&self) -> Arc<T> {
match self.them.lock().upgrade() {
Some(arc) => return arc,
None => unreachable!(),
}
}
}
to use it
pub struct Test {
me: MeKeeper<Self>,
foo:i8,
}
impl Test {
pub fn new() -> Arc<Self> {
let arc = Arc::new(Test {
me: MeKeeper::new(),
foo:42
});
arc.me.save(&arc);
arc
}
}
now when an instance of Test wants to call a function that requires it to pass in an Arc it does:
fn nargle(){
let me = me.get();
Ooddle::fertang(me,42);// fertang needs an Arc<T>
}
the weak use is what the shared_from_this does so as to prevent refcount deadlocks, I stole that idea.
The unreachable path is safe because the only place that can call MeKeeper::get is the instance of T (Test here) that owns it and that call can only happen if the T instance is alive. Hence no none return from weak::upgrade

How best to deal with struct field that can change types

I'm working with a library that uses Rust types to keep track of state. As a simplified example, say you have two structs:
struct FirstStruct {}
struct SecondStruct {}
impl FirstStruct {
pub fn new() -> FirstStruct {
FirstStruct {}
}
pub fn second(self) -> SecondStruct {
SecondStruct {}
}
// configuration methods defined in this struct
}
impl SecondStruct {
pub fn print_something(&self) {
println!("something");
}
pub fn first(self) -> FirstStruct {
FirstStruct {}
}
}
And to actually use these structs you usually follow a pattern like so, after printing you may stay in second state or go back to first state depending on how you're using the library:
fn main() {
let first = FirstStruct::new();
let second = first.second(); // consumes first
second.print_something();
// go back to default state
let _first = second.first();
}
I want to create my own struct that handles the state changes internally and simplifies the interface. This also lets me have a single mutable reference around that I can pass to other functions and call the print method. Using it should look something like this:
fn main() {
let mut combined = CombinedStruct::new(FirstStruct::new());
combined.print();
}
I've come up with the following solution that works, at least in this simplified example:
enum StructState {
First(FirstStruct),
Second(SecondStruct),
}
struct CombinedStruct {
state: Option<StructState>,
}
impl CombinedStruct {
pub fn new(first: FirstStruct) -> CombinedStruct {
CombinedStruct {
state: Some(StructState::First(first)),
}
}
pub fn print(&mut self) {
let s = match self.state.take() {
Some(s) => match s {
StructState::First(first) => first.second(),
StructState::Second(second) => second,
},
None => panic!(),
};
s.print_something();
// If I forget to do this, then I lose access to my struct
// and next call will panic
self.state = Some(StructState::First(s.first()));
}
}
I'm still pretty new to Rust but this doesn't look right to me. I'm not sure if there's a concept I'm missing that could simplify this or if this solution could lead to ownership problems as my application gets more complicated. Is there a better way to do this?
Playground link
I once had a similar problem and went basically with your solution, but I avoided the Option.
I.e. I basically kept your
enum StructState {
First(FirstStruct),
Second(SecondStruct),
}
If an operation tries to convert a FirstStruct to a SecondStruct, I introduced a function try_to_second roughly as follows:
impl StructState {
fn try_to_second(self) -> Result<SecondState, StructState> {
/// implementation
}
}
In this case, an Err indicates that the StructState has not been converted to SecondStruct and preserves the status quo, while an Ok value indicates successfull conversion.
As an alternative, you could try to define try_to_second on FirstStruct:
impl FirstStruct {
fn try_to_second(self) -> Result<FirstStruct, SecondStruct> {
/// implementation
}
}
Again, Err/Ok denote failure/success, but in this case, you have more concrete information encoded in the type.

How are you able to create partially initialised structs?

When creating a struct in Rust it seems like it's difficult to create one without having all of the fields set. For example with the following code
struct Connection {
url: String,
stream: TcpStream
}
You aren't able to set url without giving stream as well.
// Compilation error asking for 'stream'
let m = Connection { url: "www.google.com".to_string() };
How are you able to create these references that might be Option<None> until a later time?
The best I have found is using the Default trait, but I'd rather not have to create the TcpStream until a later time than when the struct is initialised. Am I able to do this with something like a Box?
One thing you can do is to wrap the TcpStream in an Option, i.e. Option<TcpStream>. When you first construct the struct, it'll be None, and when you initialize it you make it self.stream = Some(<initialize tcp stream>). Wherever you use the TCPStream, you'll have to check if it's Some, i.e. if it has already been initialized. If you can guarantee your behavior then you can just unwrap(), but it's probably better to make a check anyways.
struct Connection {
url: String,
stream: Option<TcpStream>
}
impl Connection {
pub fn new() -> Connection {
Connection {
url: "www.google.com".to_string(),
stream: None,
}
}
pub fn initialize_stream(&mut self) {
self.stream = Some(TcpStream::connect("127.0.0.1:34254").unwrap());
}
pub fn method_that_uses_stream(&self) {
if let Some(ref stream) = self.stream {
// can use the stream here
} else {
println!("the stream hasn't been initialized yet");
}
}
}
This is similar to what is done in Swift, in case you're familiar with that language.
All fields indeed have to be initialized when creating the struct instance (there is no null in Rust) so all the memory is allocated.
There is often a dedicated method (like new) that sets default values for fields which are supposed to be modified at a later stage.
I'd use the Box when you don't know the size of the field (like Vec does).
As an extension to Jorge Israel Peña's answer, you can use a builder. The builder has all the optional fields and produces the final value without Options:
use std::net::TcpStream;
struct ConnectionBuilder {
url: String,
stream: Option<TcpStream>,
}
impl ConnectionBuilder {
fn new(url: impl Into<String>) -> Self {
Self {
url: url.into(),
stream: None,
}
}
fn stream(mut self, stream: TcpStream) -> Self {
self.stream = Some(stream);
self
}
fn build(self) -> Connection {
let url = self.url;
let stream = self
.stream
.expect("Perform actual error handling or default value");
Connection { url, stream }
}
}
struct Connection {
url: String,
stream: TcpStream,
}
impl Connection {
fn method_that_uses_stream(&self) {
// can use self.stream here
}
}
This means that you don't have to litter your code with checks to see if the stream has been set yet.
See also:
How to initialize a struct with a series of arguments
Do Rust builder patterns have to use redundant struct code?
Is it possible to create a macro to implement builder pattern methods?
How to write an idiomatic build pattern with chained method calls in Rust?

Resources