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?
Related
I have a struct called Connection that receives either a tokio::net::TcpStream or a tokio::net::UnixStream to talk to a remote server. Given that Rust doesn't have constructors I added a static new() method to my struct and perform an authentication handshake there before passing the instance of the stream to a new instance of Connection and returning that from new() to my end users.
My problem is how to create a temporary that can be set to either a UnixStream or a TcpStream so I can operate on it during the message exchange that makes the handshake. Since UnixStream and TcpStream don't have a common parent I'm at a loss on how to achieve this:
pub struct Configuration {
tcp_socket: Option<SocketAddr>,
unix_socket: Option<PathBuf>,
}
pub(crate) struct Connection {
tcp: Option<TcpStream>,
unix: Option<UnixStream>,
}
impl Connection {
pub(crate) async fn new(configuration: &Configuration) -> Result<Connection, Box<dyn std::error::Error>> {
let mut stream;
if configuration.unix_socket().is_some() {
stream = UnixStream::connect(configuration.unix_socket().unwrap()).await?;
} else {
stream = TcpStream::connect(configuration.tcp_socket().unwrap()).await?;
}
// Handshake code goes here...
let conn = Connection {
tcp: Some(stream),
unix: None,
};
Ok(conn)
}
You can either use an enum like this:
pub(crate) enum Connection{
Tcp(TcpStream),
Unix(UnixStream),
}
and match that everywhere you access it or implement a trait for both streams with the common functionality. This trait can be taken as a generic which would evaluate at compile time which version it is.
Minimal Example:
pub(crate) trait ExampleStream{
fn connect<A>(address: A) -> Result<Self, Error>;
}
The enum option is closest to what you've written so far so I would suggest doing it that way.
I'm new to rust and am currently rewriting some of my old java code in it. It's my first time not programming in OOP so this is strange and new to me.
I'm having some problems understanding how to implement a different method (with the same name) to each instance of a struct. In essence I'm trying to achieve behavior similar to abstract Class, extends, #override in Java.
Perhaps this example is better at explaining what exactly I'm trying to do. In it I try to implement different execute() logic to each instance of AbstractNode.
Create a struct called "AbstractNode" that holds some data and has 3 methods associated with it (validate(), log(), execute())
struct AbstractNode {
pub data: //data here
pub validate: bool,
pub log: String,
}
trait NodeFunctions {
fn validate(&self)->bool{false}
fn log(&self){println!("/")}
fn execute(&self){}
}
impl NodeFunctions for AbstractNode{
fn validate(&self)->bool{
self.validate
}
fn log(&self){
println!("{}/", self.log);
}
fn execute(&self){
//--this function is the problem, because I don't want its behavior to be
//shared between all instances of Abstract node--
}
}
I then instantiate several nodes. If possible I would also like to define the body of the execute() somewhere in here.
let node1 = AbstractNode{
data: //data
validate: false,
log: "node1".to_string(),
};
let node2 = AbstractNode{
data: //data
validate: 1>0,
log: "node2".to_string(),
};
let node3 = AbstractNode{
data: //data
validate: true,
log: "node3".to_string(),
};
//...
It is called from main like so. If the condition in validate() is true first the log() method is executed, which is the same for all nodes. Then the execute() which is not the same for all nodes.
fn main(){
let mut node_tree = vec![
node1,
node2,
node3
//...
];
for node in node_tree.iter() {
if node.validate(){
node.log();
node.execute(); //<--
break;
}
};
}
Each node should be able to hold different logic under the execute() method and I don't know how I could define this specific behavior.
I hope this question is clear enough. If you don't understand what I'm traying to achieve, please ask additional questions.
Ty in advance.
You could somewhat replicate it using closures. However, you'll still end up with parts that can't be generic per Node if you also want to be able to mutate it within the closure.
I've renamed and removed some parts, to simplify the examples.
First, you'll need a NodeData type, which holds your data. I'm assuming you want to be able to mutate it within the "execute" method. Then you'll need a Node type, which holds the data, along with the boxed closure for that Node instance.
struct NodeData {}
struct Node {
data: NodeData,
f: Box<dyn Fn(&mut NodeData)>,
}
Then we'll implement a method for creating a Node instance, along with the execute method that calls the closure.
This is where the limitation of using closures appears. You cannot pass it a mutable reference to the Node itself. Because the Node becomes borrowed when you access self.f to call the closure.
impl Node {
fn with<F>(f: F) -> Self
where
F: Fn(&mut NodeData) + 'static,
{
Self {
data: NodeData {},
f: Box::new(f),
}
}
fn execute(&mut self) {
(self.f)(&mut self.data);
}
}
An example of using it would then look like this:
let mut nodes: Vec<Node> = vec![];
nodes.push(Node::with(|_node_data| {
println!("I'm a node");
}));
nodes.push(Node::with(|_node_data| {
println!("I'm another node");
}));
nodes.push(Node::with(|_node_data| {
println!("I'm also a node");
}));
for node in &mut nodes {
node.execute();
}
Now, again this works. But NodeData cannot be generic, as then modifying the data in the closure becomes increasingly difficult.
Of course you could defer to having the NodeData be a HashMap, and that way you can store anything with a String key and some enum value.
While you didn't want to have separate types. This does somewhat make it easier, as all node types can have different kinds of data.
Because now we can have a single trait Node which has the execute method.
trait Node {
fn execute(&mut self);
}
Now define multiple types and implement Node for each of them. Again, the two good things of using a trait instead of closure is:
Every node you define, can contain any kind of data you'd like
In this case execute will actually be able to modify Self, which the closure solution cannot.
struct NodeA {}
struct NodeB {}
struct NodeC {}
impl Node for NodeA {
fn execute(&mut self) {
println!("I'm a node");
}
}
impl Node for NodeB {
fn execute(&mut self) {
println!("I'm another node");
}
}
impl Node for NodeC {
fn execute(&mut self) {
println!("I'm also a node");
}
}
You can still have a single Vec of nodes as the traits can easily be boxed.
let mut nodes: Vec<Box<dyn Node>> = vec![];
nodes.push(Box::new(NodeA {}));
nodes.push(Box::new(NodeB {}));
nodes.push(Box::new(NodeC {}));
for node in &mut nodes {
node.execute();
}
You could have AbstractNode store a closure that takes a reference to Self:
struct AbstractNode {
pub validate: bool,
pub log: String,
pub executor: Box<dyn Fn(&Self)>
}
The NodeFunctions implementation for AbstractNode would simply call the executor closure:
impl NodeFunctions for AbstractNode {
fn execute(&self) {
(self.executor)(&self)
}
// ...
}
Now, everytime you create a new instance of an AbstractNode, you can have a custom executor function. The executor takes a reference to self and can therefore access the node's data:
let node1 = AbstractNode {
validate: false,
log: "node1".to_string(),
executor: Box::new(|n| println!("Executing node #1. Is Valid? {}", n.validate))
};
// => Executing node #1. Is Valid? true
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
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.
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)
How to return a reference to a sub-value of a value that is under a mutex?
(5 answers)
Returning a RWLockReadGuard independently from a method
(2 answers)
How can I store a Chars iterator in the same struct as the String it is iterating on?
(2 answers)
Closed 3 years ago.
I would like to wrap a low-level third-party API with my own struct and functions to make it more friendly. Unfortunately, the third-party API needs a reference to a socket in its constructor, which means I'd like my Struct to "own" the socket (someone has to own it so that it can be borrowed, right? and I'd like that hidden as an implementation detail in my API).
The third-party API looks something like this:
struct LowLevelApi<'a> {
stream: &'a mut TcpStream,
// ...
}
impl<'a> LowLevelApi<'a> {
pub fn new(socket: &'a mut TcpStream, ... ) -> LowLevelApi<'a> {
// ...
}
}
I would like to make the interface to my function look like:
pub fn new(host: String, port: u16, ...) -> HighLevelApi {
// ...
}
I tried this:
pub struct HighLevelApi<'a> {
stream: TcpStream,
low: LowLevelApi<'a>
}
impl <'a> HighLevelApi<'a> {
pub fn new(host: String, port: u16) -> HighLevelApi<'a> {
// Ignore lack of error checking for now
let mut stream = TcpStream::connect(format!("{}:{}", host, port)).unwrap();
HighLevelApi {
stream,
low: LowLevelApi::new(&mut stream)
}
}
}
Rust is (rightly) angry: It has no way of knowing that I'm not going to do something bad with the low field later. And even worse, I would need to somehow guarantee that when my structure gets dropped, low gets dropped first, and stream second (since by that point, any relationship between the two is lost - or rather, there never is/was a relationship between the two).
(actually, it's worse than that, because the stream local variable gets moved into the new struct, so the local can't possibly be borrowed by LowLevelApi, but I can't think of a way to initialize HighLevelApi with the stream from the struct, since there's no way to get a handle to that from within the struct's initialization, is there? But based on my guess about what would happen in the paragraph above, it doesn't really matter since it still wouldn't do what I wanted)
What are examples of the various techniques that can be used to store a wrap a third-party (not under my control) struct that needs a reference to something?
The Rental crate seems to do what is needed here, albeit with documentation and examples that leave a lot to the imagination (i.e. trial and error).
Here's roughly what solves this
rental! {
pub mod rentals {
#[rental_mut]
pub struct Wrapper {
stream: Box<TcpStream>,
low: LowLevelApi<'stream>
}
}
}
pub struct HighLevelApi {
wrapper: rentals::Wrapper
}
impl HighLevelApi {
pub fn new(host: String, port: u16) -> HighLevelApi {
Api {
// Ignore lack of error checking for now
wrapper: rentals::Wrapper::new(
Box::new(TcpStream::connect(format!("{}:{}", host, port)).unwrap()),
|s| LowLevelApi::new(s)
)
}
}
pub fn do_something(&mut self) {
self.wrapper.rent_mut(|ll| ll.do_something()) // ll is the LowLevelApi
}
}
I noticed two important things that made this work:
The lifetime name on low in the Wrapper struct must match the name of the "owning" field (in this case "'stream")
You never get direct access to the reference - you get it through a callback/closure:
In the auto-generated constructor (new()) the second parameter isn't a LowLevelApi, it's a closure that gets the &mut TcpStream, and that closure is then expected to return a LowLevelApi
When you want to actually use the LowLevelApi you can "rent" it, hence the wrapper.rent_mut(f) where f is the closure that gets passed a LowLevelApi (ll) and can do what it needs
With these facts, the rest of the Rental documentation makes a lot more sense.