Ready or pending future depending on a condition - rust

I need to save a ready or pending future in a variable depending on a condition.
Would be nice if I could do this:
let f = futures::future::ready(true);
But the API provides two different functions, which have different return types, so, this does not work either:
let f = if true { futures::future::ready(()) } else { futures::future::pending::<()>() }
I understand that I can implement my own future for this, but I wonder if there is a way to make the if expression work?

You can use the futures::future::Either type:
use futures::future::Either;
use std::future::{pending, ready, Future};
pub fn pending_or_ready(cond: bool) -> impl Future<Output = ()> {
if cond {
Either::Left(ready(()))
} else {
Either::Right(pending())
}
}
(Playground)

Related

How can I communicate whether side effects have been successful or not?

With the Rust project I am working on I would like to keep the code as clean as I can but was having issues with side effects - more specifically how to communicate whether they have been successful or not. Assume we have this enum and struct (the struct may contain more members not relevant to my question):
enum Value{
Mutable(i32),
Constant(i32),
}
struct SomeStruct {
// --snip--
value: Value
}
I would like to have a function to change value:
impl SomeStruct {
fn change_value(&mut self, new_value: i32) {
match self.value {
Value::Mutable(_) => self.value = Value::Mutable(new_value),
Value::Constant(_) => (), /* meeeep! do not do this :( */
}
}
}
I am now unsure how to cleanly handle the case where value is Value::Constant.
From what I've learned in C or C++ you would just return a bool and return true when value was successfully changed or false when it wasn't. This does not feel satisfying as the function signature alone would not make it clear what the bool was for. Also, it would make it optional for the caller of change_value to just ignore the return value and not handle the case where the side effect did not actually happen. I could, of course, adjust the function name to something like try_changing_value but that feels more like a band-aid than actually fixing the issue.
The only alternative I know would be to approach it more "functionally":
fn change_value(some_struct: SomeStruct, new_value: i32) -> Option<SomeStruct> {
match self.value {
Value::Mutable(_) => {
let mut new_struct = /* copy other members */;
new_struct.value = Value::Mutable(new_value);
Some(new_struct)
},
Value::Constant(_) => None,
}
}
However, I imagine if SomeStruct is expensive to copy this is not very efficient. Is there another way to do this?
Finally, to give some more context as to how I got here: My actual code is about solving a sudoku and I modelled a sudoku's cell as either having a given (Value::Constant) value or a guessed (Value::Mutable) value. The "given" values are the once you get at the start of the puzzle and the "guessed" values are the once you fill in yourself. This means changing "given" values should not be allowed. If modelling it this way is the actual issue, I would love to hear your suggestions on how to do it differently!
The general pattern to indicate whether something was successful or not is to use Result:
struct CannotChangeValue;
impl SomeStruct {
fn change_value(&mut self, new_value: i32) -> Result<(), CannotChangeValue> {
match self.value {
Value::Mutable(_) => {
self.value = Value::Mutable(new_value);
Ok(())
}
Value::Constant(_) => Err(CannotChangeValue),
}
}
}
That way the caller can use the existing methods, syntax, and other patterns to decide how to deal with it. Like ignore it, log it, propagate it, do something else, etc. And the compiler will warn that the caller will need to do something with the result (even if that something is to explicitly ignore it).
If the API is designed to let callers determine exactly how to mutate the value, then you may want to return Option<&mut i32> instead to indicate: "I may or may not have a value that you can mutate, here it is." This also has a wealth of methods and tools available to handle it.
I think that Result fits your use-case better, but it just depends on the flexibility and level of abstraction that you're after.
For the sake of completeness with kmdreko's answer, this is the way you would implement a mut-ref-getter, which IMO is the simpler and more flexible approach:
enum Value {
Mutable(i32),
Constant(i32),
}
impl Value {
pub fn get_mut(&mut self) -> Option<&mut i32> {
match self {
Value::Mutable(ref mut v) => Some(v),
Value::Constant(_) => None,
}
}
}
Unlike the Result approach, this forces the caller to consider that setting the value may not be possible. (Granted, Result is a must_use type, so they'd get a warning if discarding it.)
You can write a proxy method on SomeStruct that forwards the invocation to this method:
impl SomeStruct {
pub fn get_mut_value(&mut self) -> Option<&mut i32> {
self.value.get_mut()
}
}

Generics<T> that accept String, &str and primitive value

I apologize in advance as this may somewhat dumb question.
I was trying to create the function that simply return the bool result of
whether the given value is prime number or not.
I wanted the function to both accept the String, &str and primitive value.
Is there anyway that I can make this possible.
pub fn prime<T>(val: T) -> bool
where T: ToPrimitive {
let val = val.to_i64().unwrap();
for i in 2..=val {
if val % i == 0 {
return false;
}
if i*i >= val {
break;
}
}
true
}
If you are concerned with performance, leave it as is. You are already accepting all integer types. Conversion from strings should happen elsewhere. (as already mentioned by the other answers)
That said, to actually fulfill your request, here is a horribly inefficient but simple solution to your problem :)
pub fn prime<T>(val: T) -> bool
where
T: ToString,
{
let val: u64 = val.to_string().parse().unwrap();
for i in 2..val {
if val % i == 0 {
return false;
}
if i * i >= val {
break;
}
}
true
}
fn main() {
println!("{:?}", prime(17));
println!("{:?}", prime("17"));
println!("{:?}", prime(String::from("17")));
}
true
true
true
On a more serious note ... your own solution and all of the answers convert the input into another type.
If you skip that and instead use the given type directly, you could potentially get a speed boost.
For that to work, though, I had to switch from i * i >= val to ..=val.sqrt().
pub fn prime<T>(val: T) -> bool
where
T: num::PrimInt + num::integer::Roots,
{
let two = T::one() + T::one();
for i in num::range_inclusive(two, val.sqrt()) {
if val % i == T::zero() {
return false;
}
}
true
}
fn main() {
println!("{:?}", prime(17));
}
true
As a further note, you could rewrite the entire for loop with the all iterator method:
pub fn prime<T>(val: T) -> bool
where
T: num::PrimInt + num::integer::Roots,
{
let two = T::one() + T::one();
num::range_inclusive(two, val.sqrt()).all(|i| val % i != T::zero())
}
fn main() {
println!("{:?}", prime(17));
}
true
I wanted the function to both accept the String, &str and primitive value.
Is there anyway that I can make this possible.
You'd have to create your own trait to unify the feature: while Rust has grown the TryFrom trait, in the stdlib currently it's only used for faillible integer -> integer conversions (e.g. i64 to u8). String -> integer conversions remain on the older FromStr trait, and it's unclear that there's any plan to migrate.
I would agree with #cameron1024 though, doing this conversion in the callee increases the complexity without making much sense, if the callee takes a string I would expect it to handle and report validation / conversion errors to the source of the values. The prime of a string doesn't really make sense.
Firstly, do you really want to be able to check if strings are prime? You probably don't want someone to be able to write prime("hello").
Assuming you're fine with numbers, I'd just use Into<u128> as the trait bound:
fn prime<T: Into<u128>>(t: T) -> bool {
let val = t.into();
// rest of the logic
}
So what about strings and signed integers?
IMO, you should convert these at the call-site, which allows for better error handling, rather than just unwrap():
/// strings
prime("123".parse()?);
prime(String::from("123").parse()?);
/// signed ints
prime(u128::try_from(123i8)?);
This way, you can use ? to correctly handle errors, and make prime panic-free.
If you really want to not have to convert at the callsite, you could use a custom trait:
trait TryIntoU128 {
type Error;
fn try_into_u128(self) -> Result<u128, Self::Error>;
}
Then you could implement this on various types:
impl TryIntoU128 for String {
type Error = ParseIntError;
fn try_into_u128(self) -> Result<u128, Self::Error> {
self.parse()
}
}
// etc
Then you can use this trait bound for your prime function instead

How to cleanly implement "waterfall" logic in Rust

I have a collection of types, representing various older and newer versions of my data schema:
struct Version1;
struct Version2;
struct Version3;
struct Version4;
These types can be migrated between each other, one at a time:
impl Version1 { fn migrate_to_v2(self) -> Version2 { Version2 } }
impl Version2 { fn migrate_to_v3(self) -> Version3 { Version3 } }
impl Version3 { fn migrate_to_v4(self) -> Version4 { Version4 } }
I have an enum containing all of these versions, which is the data format I read from the disk:
enum Versioned {
V1(Version1),
V2(Version2),
V3(Version3),
V4(Version4),
}
I'd like to write a function that performs a full migration of a Versioned object to Version4. There are various ways to do it, but all of them have obvious flaws; my question is, are there any other solutions I've overlooked?
Call the methods directly. The problem with this is exponential blowup; as I add more versions over the lifespan of this product, the size of this code will blow up quadratically:
fn migrate_versioned(versioned: Versioned) -> Version4 {
match versioned {
V1(data) => data.migrate_to_v2().migrate_to_v3().migrate_to_v4(),
V2(data) => data.migrate_to_v3().migrate_to_v4(),
V3(data) => data.migrate_to_v4(),
V4(data) => data,
}
}
Use a series of chained if lets. This requires round-tripping through the enum type, and we lose the exhaustiveness checking of a match:
fn migrate_versioned(mut versioned: Versioned) -> Version4 {
use Versioned::*;
if let V1(data) = versioned {
versioned = V2(data.migrate_to_v2());
}
if let V2(data) = versioned {
versioned = V3(data.migrate_to_v3());
}
if let V3(data) = versioned {
versioned = V4(data.migrate_to_v4());
}
if let V4(data) = versioned {
return data;
}
unreachable!();
}
Use a loop. This restores the exhaustiveness checking that was lost in the if let version, but we lose a syntactic halting guarantee, and still have the other flaws from if let:
fn migrate_versioned(mut versioned: Versioned) -> Version4 {
loop {
versioned = match versioned {
V1(data) => V2(data.migrate_to_v2()),
V2(data) => V3(data.migrate_to_v3()),
V3(data) => V4(data.migrate_to_v4()),
V4(data) => break data,
};
}
}
Some chained traits. This is better than the others but is very heavy on boilerplate:
trait ToV2: Sized {
fn migrate_to_v2(self) -> Version2;
}
impl ToV2 for Version1 { ... }
trait ToV3: Sized {
fn migrate_to_v3(self) -> Version3;
}
impl ToV3 for Version2 { ... }
impl<T: ToV2> ToV3 for T {
fn migrate_to_v3(self) -> Version3 { self.migrate_to_v2().migrate_to_v3() }{
}
trait ToV4: Sized {
fn migrate_to_v4(self) -> Version4;
}
impl ToV4 for Version3 { ... }
impl<T: ToV3> ToV4 for T {
fn migrate_to_v4(self) -> Version3 { self.migrate_to_v3().migrate_to_v4() }{
}
fn migrate_versioned(versioned: Versioned) -> Version4 {
match versioned {
V1(data) => data.migrate_to_v4(),
V2(data) => data.migrate_to_v4(),
V3(data) => data.migrate_to_v4(),
V4(data) => data,
}
}
Various macro-based solutions. Generally these use a macro to produce one of the noisy solutions (such as the trait version or the direct call version). Because of trickiness related to creating chaining calls using macro repetition rules (which requires a complex recursive macro, as far as I can tell), these tend to be extremely noisy, to the point where it can't meaningfully be said to be a complexity saver: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=c8b8bed94afe654bbee7cfabfe24c784.
Are there any solutions that I've missed here? Conceptually it seems straightforward to want to do something like this:
// V1 starts here
let v2 = v1.migrate_to_v2();
// V2 starts here
let v3 = v2.migrate_to_v3();
// V3 starts here
let v4 = v3.migrate_to_v4();
// v4 starts here
But it's not at all clear to me how (if at all) it's possible to express the control flow for a solution that looks as simple as that.
One way would be a pair of traits. The first trait determines how to get to the next version, and the second trait would complete the chain.
pub trait Migrate {
type NextVersion;
fn migrate(self) -> Self::NextVersion;
}
pub trait MigrateToLatest {
type Latest;
fn migrate_to_latest(self) -> Self::Latest;
}
/// If the next version knows how to MigrateToLatest, call their implementation
impl<M: Migrate> MigrateToLatest for M
where
M::NextVersion: MigrateToLatest,
{
type Latest = <M::NextVersion as MigrateToLatest>::Latest;
#[inline]
fn migrate_to_latest(self) -> Self::Latest {
self.migrate().migrate_to_latest()
}
}
/// Start the waterfall for the LatestVersion type alias (below).
impl MigrateToLatest for LatestVersion {
type Latest = Self;
fn migrate_to_latest(self) -> Self::Latest {
self
}
}
Then we just need to implement Migrate for the previous version every time we have a new release.
impl Migrate for Version1 {
type NextVersion = Version2;
fn migrate(self) -> Self::NextVersion {
Version2
}
}
impl Migrate for Version2 {
type NextVersion = Version3;
fn migrate(self) -> Self::NextVersion {
Version3
}
}
impl Migrate for Version3 {
type NextVersion = Version4;
fn migrate(self) -> Self::NextVersion {
Version4
}
}
When a new version is version is made, the only changes that are needed are updating the LatestVersion and adding a new Migrate from the previous version.
/// Declare the latest version which ends the waterfall
type LatestVersion = Version4;
This approach means we only need to deal with the latest version and don't need to write out the entire chain ourselves.
You may also find it helpful to write your Versioned enum in a macro since you likely need to perform a couple uniform operations on every variant.
macro_rules! make_versioned {
($($name:ident: $type:ty),+) => {
enum Versioned {
/// Define the elements of the macro in the enum
$($name($type)),+
}
impl MigrateToLatest for Versioned {
type Latest = LatestVersion;
fn migrate_to_latest(self) -> Self::Latest {
use Versioned::*;
match self {
// Take advantage of the macro to easily call on every variant
$($name(x) => x.migrate_to_latest()),+
}
}
}
}
}
/// Define the elements in the Versioned enum
make_versioned! {
V1: Version1,
V2: Version2,
V3: Version3,
V4: Version4
}

Is there a Rust equivalent to C++'s operator bool() to convert a struct into a boolean?

In C++, we can overload operator bool() to convert a struct to bool:
struct Example {
explicit operator bool() const {
return false;
}
};
int main() {
Example a;
if (a) { /* some work */ }
}
Can we do something simple (and elegant) in Rust so to:
pub struct Example {}
fn main() {
let k = Example {};
if k {
// some work
}
}
There's no direct equivalent of operator bool(). A close alternative would be to implement From (which will also implement Into) and call the conversion explicitly:
pub struct Example;
impl From<Example> for bool {
fn from(_other: Example) -> bool {
false
}
}
fn main() {
let k = Example;
if k.into() {
// some work
}
}
This will take ownership of Example, meaning you can't use k after it's been converted. You could implement it for a reference (impl From<&Example> for bool) but then the call site becomes uglier ((&k).into()).
I'd probably avoid using From / Into for this case. Instead, I'd create a predicate method on the type. This will be more readable and can take &self, allowing you to continue using the value.
See also:
When should I implement std::convert::From vs std::convert::Into?
Rust does not have C++'s implicit type conversion via operator overloading. The closest means of implicit conversion is through a Deref impl, which provides a reference of a different type.
What is possible, albeit not necessarily idiomatic, is to implement the not operator ! so that it returns a boolean value, and perform the not operation twice when needed.
use std::ops::Not;
pub struct Example;
impl Not for Example {
type Output = bool;
fn not(self) -> bool { false }
}
fn main() {
let k = Example;
if !!k {
println!("OK!");
} else {
println!("WAT");
}
}
Playground
You have a few options, but I'd go for one of these:
Into<bool> (From<Example>)
If your trait conceptually represents a bool, but maybe with some extra metadata, you can implement From<Example> for bool:
impl From<Example> for bool {
fn from(e: Example) {
// perform the conversion
}
}
Then you can:
fn main() {
let x = Example { /* ... */ };
if x.into() {
// ...
}
}
Custom method
If your type doesn't really represent a boolean value, I'd usually go for an explicit method:
impl Example {
fn has_property() -> bool { /* ... */ }
}
This makes it more obvious what the intent is, for example, if you implemented From<User> for bool:
fn main() {
let user = User { /* ... */ };
if user.into() {
// when does this code get run??
}
// compared to
if user.logged_in() {
// much clearer
}
}
You can implement std::ops::Deref with the bool type. If you do that, you have to call *k to get the boolean.
This is not recommended though, according to the Rust documentation:
On the other hand, the rules regarding Deref and DerefMut were designed specifically to accommodate smart pointers. Because of this, Deref should only be implemented for smart pointers to avoid confusion.
struct Example {}
impl std::ops::Deref for Example {
type Target = bool;
fn deref(&self) -> &Self::Target {
&true
}
}
fn main() {
let k = Example {};
if *k {
// some work
}
}
Playground

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.

Resources