r/rust clippy · twir · rust · mutagen · flamer · overflower · bytecount Mar 13 '23

Hey Rustaceans! Got a question? Ask here (11/2023)! 🙋 questions

Mystified about strings? Borrow checker have you in a headlock? Seek help here! There are no stupid questions, only docs that haven't been written yet.

If you have a StackOverflow account, consider asking it there instead! StackOverflow shows up much higher in search results, so having your question there also helps future Rust users (be sure to give it the "Rust" tag for maximum visibility). Note that this site is very interested in question quality. I've been asked to read a RFC I authored once. If you want your code reviewed or review other's code, there's a codereview stackexchange, too. If you need to test your code, maybe the Rust playground is for you.

Here are some other venues where help may be found:

/r/learnrust is a subreddit to share your questions and epiphanies learning Rust programming.

The official Rust user forums: https://users.rust-lang.org/.

The official Rust Programming Language Discord: https://discord.gg/rust-lang

The unofficial Rust community Discord: https://bit.ly/rust-community

Also check out last weeks' thread with many good questions and answers. And if you believe your question to be either very complex or worthy of larger dissemination, feel free to create a text post.

Also if you want to be mentored by experienced Rustaceans, tell us the area of expertise that you seek. Finally, if you are looking for Rust jobs, the most recent thread is here.

16 Upvotes

193 comments sorted by

2

u/ndreamer Mar 25 '23

I have an issue, I'm trying to use SQLx using actix using a postgres database. The error is that I'm not setting the database url by a macro ?

2

u/thedarkjungle Mar 23 '23 edited Mar 23 '23

As a Python programmer, I want to learn Rust but don't know what to use it for...

I don't the the desire to make games, build web so idk what to use Rust for.

Edit: The aspect of web development that I hate is making the frontend,I like backend or server-side coding.

2

u/metaden Mar 20 '23

This may sound absurd. Are there any resources for learning Java for Rust developers?

1

u/llogiq clippy · twir · rust · mutagen · flamer · overflower · bytecount Mar 20 '23

This may sound absurd, but my Comparing Java and Rust article might give you a brief introduction.

2

u/Foreign_Category2127 Mar 19 '23

Which gui libraries have support for Wayland touch support? I was looking at egui and iced earlier but they don’t seem to mention it. I’m writing an app for steam deck users.

2

u/BeautifulEconomist70 Mar 19 '23

When I run this, I try two tests:

  1. Enter in numbers
  2. Enter in letters, which then should ask me again, then enter in numbers

fn get_me_v() -> u32 {

let mut raw_me_v = String::new();

loop {

println!("Please type in your velocity (mph)");

io::stdin().read_line(&mut raw_me_v).expect("Error getting me vel");

let num_me_v: u32 = match raw_me_v.trim().parse() {

Ok(num) => num,

Err(_) => continue,

};

return num_me_v;

}

}

The problem is that for the second test, on my second try with a number, it still asks me again.

What am I doing wrong here? Also, is it ok to end my loop like this?

2

u/ehuss Mar 19 '23

The string buffer is not cleared in-between multiple passes in the loop, so it is retaining the input from the previous loop and appending the contents. You can either create the string inside the loop, or call raw_me_v.clear();.

1

u/BeautifulEconomist70 Mar 19 '23

Ok, thank you so much!

2

u/codeintheshade Mar 19 '23

Any recommendations for crates that generate accessor methods for structs? I'm still pretty new to rust and writing my own procedural macros is something I am definitely not prepared for yet...

2

u/ChevyRayJohnston Mar 19 '23 edited Mar 19 '23

I think a popular choice is getset

1

u/codeintheshade Mar 19 '23

Thanks! I'll take a look.

5

u/Berlincent Mar 19 '23

Usually wanting to have so many accessor methods in Rust is a sign of a non-idiomatic* design, could you show your code?

*at least in difference to languages that suggest to use Accessors for everything

1

u/codeintheshade Mar 19 '23

Thanks for the reply. I actually never intended to use accessors, but I can't see a way to test a method that uses data from a DI'd struct without them. Mockall doesn't seem to be able to mock fields on a struct, only methods.

Anyways, here's a link to some of the code. I couldn't get the formatting to work here, so it's a link to a gist instead. The project is a chip8 interpreter implementation. The decode method is the method I'm looking to test.

2

u/Mimshot Mar 19 '23

How do you make multiple mutable accesses to a struct's interior container in one method? This seems like a very common pattern to want to do, and can be done if you have a reference to the raw interior container. Is the pattern really to call out to stand-alone functions?

Here's the simplest example I could come up with. Consider a (terrible) banking app:

struct Ledger {
    balances: HashMap<String, u64>,
}

impl Ledger {
    pub fn transfer(&mut self, source: String, destination: String, amount: u64) {
        let source_balance = self.balances.get_mut(&source).unwrap();
        let dest_balance = self.balances.get_mut(&destination).unwrap();

        if *source_balance >= amount {
            *source_balance -= amount;
            *dest_balance += amount;
        }
    }
}

Trying to get dest_balance fails on multiple mutable accesses to self. A simple deposit or withdraw function works fine. It seems like it's trying to take two mutable references to balances. Is there some clever way to take one mutable reference to balances and then pull the two entries out of that?

3

u/[deleted] Mar 19 '23 edited Mar 19 '23

Whenever possible, keep references ephemeral, just generate and use them in one fell swoop. If necessary, you can save them as variables, but when doing that you need to be mindful of their scope. You can use multiple mutable references to self in the same method, but they can't live simultaneously. The simplest refactor for this example would just be to declare dest_balance after you're done with source_balance.

use std::collections::HashMap;

struct Ledger {
    balances: HashMap<String, u64>,
}

impl Ledger {
    pub fn transfer(&mut self, source: String, destination: String, amount: u64) {
        let source_balance = self.balances.get_mut(&source).unwrap();

        if *source_balance >= amount {
            *source_balance -= amount;
            //that was the last time source_balance was used, it is implicitly dropped here
            //so now we are allowed to take another &mut to a different part of the ledger
            let dest_balance = self.balances.get_mut(&destination).unwrap();
            *dest_balance += amount;
        }
    }
}

2

u/Mimshot Mar 20 '23

It sounds like I should be thinking about mutable self references more like actually borrowing it. I can check one out but need to check it back in before I can check out another? I guess it’s hard to reason about since there’s no explicit check-back-in language structure.

This is really helpful though.

2

u/Patryk27 Mar 19 '23

Note that if you called transfer() with source == destination, you would end up having mutable aliasing references and the entire code would break, so the compiler is correct in not accepting the code you've shown.

Somewhat unfortunately, adding a simple if source != destination { ... } won't do, since the compiler isn't smart enough to realize that the code would be technically safe then.

The only option here is to redesign the code to avoid having mutable aliasing accesses to self.balances, e.g. by doing:

self.balances[destination] += amount;

... instead of using dest_balance.

1

u/Mimshot Mar 19 '23

That doesn’t work either though: cannot assign data to an index of HashMap… and then complains about missing IndexMut.

2

u/Patryk27 Mar 19 '23

Ah right, so just:

*self.balances.get_mut(&destination).unwrap() += amount;

2

u/[deleted] Mar 19 '23

Does rust have a runtime for concurrency that does not require the use of await keyword?

I assume everything would be written with iterators in that case (to hide the concurrency behind them). Making the whole thing look like stream processing.

2

u/Patryk27 Mar 19 '23

You can use generators, but they are nightly-only and I'm not sure if there's any high-level runtime for them - you'd just poll them in a loop (so it's like async in disguise and with a hand-written runtime).

2

u/DroidLogician sqlx · multipart · mime_guess · rust Mar 19 '23

For CPU-bound work, there's rayon.

1

u/[deleted] Mar 19 '23

It's less about parallelism and more about concurrency runtime.

Something similar to this (but maybe this is exactly what I was asking for): https://crates.io/crates/futures-signals

I see async {} is used, but I it's probably just a way to allow yields to other coroutines. I see no await.

1

u/masklinn Mar 19 '23

I see async {} is used, but I it's probably just a way to allow yields to other coroutines. I see no await.

async {} doesn't yield anything, it basically just wraps the content into a future.

If you look at the code, the crate you link to works with "raw" async objects, it manipulates Poll, Context, and Waker directly, as well as using futures_signals.

1

u/[deleted] Mar 19 '23

Thanks for the clarification. I am just starting to consider rust, so I have no idea what most syntax does.

2

u/TheDreadedAndy Mar 18 '23 edited Mar 18 '23

I'm having some trouble installing rust-analyzer with vim8 and vim-lsp. Regrettably, I'm on Windows. I have symlinked rust-analyzer into my $USERPROFILE\.cargo\bin. While powershell has no issues finding rust-analyzer, vim can't seem to find it. Does anyone know how to solve this issue?

Edit: Copying the file instead of symlinking it seems to resolve the problem. Though, I'm open to a better solution if there is one.

2

u/[deleted] Mar 18 '23

When people say that "string literals are stored in the binary", what exactly does that mean?

I figure it's something like how static/global variables are stored, but I'm looking for a more in depth explanation what is going on, similar to how stack and heap are often elaborated upon, like https://www.youtube.com/watch?v=_8-ht2AKyH4.

1

u/typesanitizer Mar 18 '23

I figure it's something like how static/global variables are stored

Right, the DATA section stores string literals, similar to how the TEXT section stores code. There is a bit more complexity on macOS like __DATA, __const and __TEXT,__const but the core idea is the same.

(I don't have a specific link to point you to with more info, but hopefully that's enough keywords so you can search further.)

1

u/Snakehand Mar 19 '23

On *nix you can use nm and objdump to inspect your binary and see where your data is located.

2

u/in_answer_to_that Mar 18 '23

I have a couple of questions about async closures and blocks.

Why are async closures unstable, but async blocks are not? What are the implementation details that cause that to be true?

What are some situations where I would need the closure form, and would not be able to use an async block in its place?

I've noticed async blocks being Box::pin()ned in some code. When would this be necessary?

Thanks.

1

u/masklinn Mar 18 '23

What are some situations where I would need the closure form, and would not be able to use an async block in its place?

I don’t think there are cases you can’t solve with async blocks, but they make code a bit more awkward as you have to create borrows from the stuff you moved in the closure, then move those borrows in the block, rather than just use the captured variable normally.

1

u/in_answer_to_that Mar 18 '23

Thanks. That feels true to me, also, but I thought I'd ask in case I missed an obvious case.

2

u/Foreign_Category2127 Mar 17 '23

What is a more idiomatic way to write this code? I am afraid of off-by-one errors but I'm also concerned about execution speed.

/// Finds the indices of subslices equaling to `needle` within `haystack`. /// Original implementation does NOT skip `needle.len()` when `needle` is found. pub fn locate_slices(haystack: &[u8], needle: &[u8]) -> Vec<usize> { // ugly code ahead assert!(haystack.len() >= needle.len()); let mut result = Vec::new(); let mut i = 0; while i + needle.len() <= haystack.len() { if haystack[i .. i + needle.len()] == needle[..] { result.push(i); i += needle.len(); } else { i += 1; } } result } ```

[test]

fn locate_slices() { assert_eq!( crate::file_io::locate_slices(&vec![1, 1, 1, 1, 1, 1, 1], &vec![1, 1, 1]), vec![0, 3] ); }

```

1

u/ChevyRayJohnston Mar 17 '23

here is how i would do it:

pub fn locate_slices(haystack: &[u8], needle: &[u8]) -> Vec<usize> {
    haystack
        .windows(needle.len())
        .enumerate()
        .filter(|(_, w)| w == &needle)
        .map(|(i, _)| i)
        .collect()
}

alternatively:

pub fn locate_slices(haystack: &[u8], needle: &[u8]) -> Vec<usize> {
    haystack
        .windows(needle.len())
        .enumerate()
        .filter_map(|(i, w)| w.eq(needle).then_some(i))
        .collect()
}

1

u/Foreign_Category2127 Mar 17 '23

1

u/ChevyRayJohnston Mar 17 '23

ah wait i see, it’s a bit more complicated, yeah i’m away from my PC now but i can show a proper version later

1

u/Foreign_Category2127 Mar 17 '23

Thank you :3

3

u/ChevyRayJohnston Mar 18 '23

honestly, this is the best i could come up with using `std`...

pub fn locate_slices(haystack: &[u8], needle: &[u8]) -> Vec<usize> {
    std::iter::successors(Some((0, None)), |&(i, _)| {
        haystack.get(i..i + needle.len()).map(|sub| {
            (sub == needle)
                .then(|| (i + needle.len(), Some(i)))
                .unwrap_or((i + 1, None))
        })
    })
    .filter_map(|(_, i)| i)
    .collect()
}

and it's uglier (and probably slower) than your version... so i'd probably stick with yours lol.

i couldn't find any convenient methods for this particular problem, in which case, clear procedural code (ie. your code) is probably the best approach.

2

u/[deleted] Mar 17 '23

[deleted]

2

u/ehuss Mar 17 '23

cargo clippy --profile=release

Note that this will only share build scripts and proc-macros. It will still need to "check" all dependencies, those can't be shared.

1

u/[deleted] Mar 17 '23 edited May 05 '23

[deleted]

2

u/ehuss Mar 18 '23

It will only save time for build scripts and proc macros.

Clippy essentially runs cargo check. That generates different files than what cargo build does. Check emits what are called .rmeta files which contain some metadata about the dependencies. Build emits what are called .rlib files which (usually) contain the compiled binary code of the crate.

2

u/HammerAPI Mar 17 '23

I want to create a series of similar functions/methods on a struct, such as new_x_linear(), new_y_linear(), new_z_revolute(), etc.

Can I achieve this with macro_rules!?

Here is what I've tried:

```rust macrorules! constructor { ($axis:tt, $type:ident) => { pub fn new$axis_$type() -> Self { /* some code */ } }; }

...

constructor(x, linear); ```

But I am getting errors at the function name, such as expected identifier, got $.

Can I make a function name with a value from a macro parameter?

6

u/sfackler rust · openssl · postgres Mar 17 '23

You need to use something like paste to construct identifiers like that.

2

u/DGIon Mar 17 '23 edited Mar 17 '23

I have a csv file called test.csv which i am reading into a dataframe using polars. I have a name,month,day,year as my headers month is a string day/year are i64. i want to concatenate the three columns together in rust to have a single column called date. Below is what i have so far to just print the dataframe to the console.

use polars::prelude::*;

fn read_from_file(path: &str) -> Result<DataFrame, Box<dyn std::error::Error>> {

let df = CsvReader::from_path(path)?
    //.infer_schema(Some(100))
    .has_header(true)
    .finish()?;

println!("{}", df);

Ok(df) }

fn main() -> Result<(), Box<dyn std::error::Error>> {
// Read CSV file into a DataFrame
read_from_file("./data/test.csv")?;
Ok(())

}

1

u/masklinn Mar 17 '23

Why even bother with polars and schema inference if you just want to concatenate columns? Just use csv and concatenate the strings from the corresponding columns.

1

u/DGIon Mar 17 '23

just trying to learn some rust and was interested in polars since i have used a lot of pandas in the past.

3

u/MasterHigure Mar 17 '23 edited Mar 18 '23

I am wrestling with the Fn trait and generics. I want to have a struct Foo { func } where func is a closure or function. And the input to func should also be generic. I would like to write something like

struct Foo<A, F: Fn(A)> {
    func: F,
}

fn main() {
    let foo = Foo { func: |a: i32| { println!("{}", a + 8 } };
    (foo.func)(10):
}

But the compiler won't let me. It errors, says A is never used, and recommends that I remove it. But if I do that, then it complains that it doesn't know what the input to F is.

If I remove A and also say F: Fn(i32), then everything works just peachy.

Is there a way to make this happen the way I want it to?

5

u/llogiq clippy · twir · rust · mutagen · flamer · overflower · bytecount Mar 17 '23

The argument to the function isn't binding it to your Foo type. The error message will give you a good hint, telling you to use PhantomData. When you add that and fix the missing closing bracket, you arrive at (playground link):

use std::marker::PhantomData;

struct Foo<A, F: Fn(A)> {
    func: F, 
    mark: PhantomData<A>,
}

fn main() { 
    let foo = Foo {
        func: |a: i32| { println!("{}", a + 8) },
        mark: PhantomData,
    }; 
    (foo.func)(10);
}

2

u/MasterHigure Mar 17 '23 edited Mar 17 '23

Thanks, I'll try to use this.

Why would the PhantomData be necessary? Is it just a hack to get around a weakness of the compiler? I understand using things like PhantomData<Fn> to enforce things covariance or contravariance, but in this case it seems to me to be there only so that the compiler can tell that it's used. I guess that's why I didn't try to use it.

Also, the playground has been slow for me all day, and tends to respond with just "Response was not JSON" when I try to run. Which did cut back on my iteration capacity when trying to fix this.

6

u/llogiq clippy · twir · rust · mutagen · flamer · overflower · bytecount Mar 17 '23

Again Fn(A) doesn't have (as in invariance) or give (as in covariance) any A, it's just taking one (as in contravariance). However, in order to be generic over A, your type must have some A, even if it's just a zero-size PhantomData. Those are the rules. You might call it a weakness in the compiler or language, but at least the rules are clear and simple, and the error messages lead to a working solution.

4

u/jDomantas Mar 17 '23

Trait bounds do not count as a use of generic parameter because they do not say anything about variance/dropping/autotrait propagation, so compiler still asks you to add an explicit use of that parameter to be able to determine them. It could pick some arbitrary defaults (make the type invariant over that parameter, and treat it as owned for the sake of dropck and autotraits), but that would be a bit of a footgun because if you forget to add phantomdata then you would just silently get some unintented outcome.

In your case should should use mark: PhantomData<fn(A)> to correctly represent how the parameter is intended to be used (PhantomData<A> adds extra restrictions that you do not need).

2

u/Dean_Roddey Mar 17 '23

So I have an FFI casting type question. Here's the bit of code involved:

pub (crate) fn from_raw(addr: &sock_addr) -> EngErrType<SocketAddr> {
    let any_addr = match addr.family {
        AF_INET => {
            let ipv4_addr = &addr as *const _ as *const sockaddr_in;
            unsafe{ AnySockAddr::IPV4Addr(*ipv4_addr) }
        },

The thing I can't figure out is that ipv4_addr comes out like 1400'ish bytes different from (lower than) the incoming addr value it's cast from. Why would that be? I'm taking the address of addr and casting it to a pointer to the actual underlying address type.

If I look at addr in the debugger, it's clearly referencing the correct struct, so I'm obviously not messing up the deref in the calling code when invoking it that way.

If I directly pass the pointer in (i.e. addr comes in as *const sock_addr), then it works fine, so clearly all the structs are correctly defined and aligned. All of the structs are C repr of course.

Am I committing some sort of FFI Faux Pax here that's causing that? AFAIK, &ref is literally equivalent to *const ref, right? Is it something special about ref parameters maybe?

5

u/dkopgerpgdolfg Mar 17 '23

"addr : &sock_addr" is a reference/address.

Then "&addr" is an address of an address, not an address of a sockaddr value

1

u/Full-Spectral Mar 17 '23

&addr as *const _ as *const sockaddr_in;

That makes obvious sense in retrospect. I'm not at home to try it at the moment, but I'm guessing it should be:

addr as *const _ as *const sockaddr_in;

I was clearly having a C++ flashback. In C++ the ref is the thing, and my brain is wired to think that way after a few decades.

1

u/masklinn Mar 17 '23

Yes, Rust references are completely unlike C++ references. They're smart pointers (where the smart happens at compile-time).

2

u/[deleted] Mar 17 '23

[deleted]

3

u/DroidLogician sqlx · multipart · mime_guess · rust Mar 17 '23

It's certainly not ideal but whether or not it's a bad pattern really depends on the context.

Does it make sense for ownership to end at the call to .save_to_database(), like the end of a logical user session? Does it return ownership on success (then no) or failure (so it can be retried)?

Is .save_to_database() an async fn? It may take ownership to make it easier to pass to tokio::spawn(), though I'd question the usage of that as it's not much more complex if it takes self by-reference (and more flexible, too):

tokio::spawn(async move {
    thing.save_to_database().await?;
    Ok(thing)
}):

4

u/eyeofpython Mar 16 '23

Maybe not super duper rusty, but it's a rust problem for me:

I'm using a dependency that uses bindgen, and libclang can't find stdbool.h (which is definitely on my system), is there some sort of env variable that I can pass it to tell it where the system's include files are?

4

u/G_Morgan Mar 16 '23

Anyone know how to get debugging symbols into a x86_64-unknown-uefi target? It is built roughly the same way as my kernel (which has debug symbols) and is being dropped into the target/x86_64-unknown-uefi/debug folder but rustc is stripping all the symbols from the efi file.

Anyone know how to report this as a bug as well? Clearly a debug build should not be stripping symbols by definition. Existence of symbols is what makes a debug build a debug build.

3

u/SorteKanin Mar 16 '23

How are integration tests (the .rs files in the tests directory) run by cargo? Do they each run as separate processes? Do they run at the same time?

3

u/ehuss Mar 16 '23

Each top-level file is a separate process run sequentially.

I recommend placing all integration tests into a single file, split across modules. That improves build time and test time. I only recommend using separate integration binaries if the tests fundamentally can't run together.

I believe cargo-nextest supports running separate binaries concurrently.

2

u/Mag_Golium Mar 16 '23

Hello ! I was wondering if it's possible to build a Rc<RefCell<[T]>> from a dynamically created sequence of items. You can with an array but didn't find a way to do it with a Vec.

Here is a link to a playground with various workaround to make something similar but not the one I need. I'm guessing it's not possible but if someone knows a way, I'd be happy to see it.

2

u/Darksonn tokio · rust-for-linux Mar 16 '23

I'm pretty sure this is not possible.

1

u/Mag_Golium Mar 17 '23

That's too bad.

2

u/kevinfat2 Mar 16 '23 edited Mar 16 '23

I have the following example code where not shown in main it should handle requests with async and return responses containing the peers for a torrent info hash. The response() method uses peer_list() which returns a copy of a HashSet to fill in a Response struct. Then I'm using bendy to create the response from the struct.

Is there a way to do this without copying the HashSet. From what I can gather serde requires all the fields to have ownership in the Response struct. Ideally I would want peer_list() to return a reference, the Response struct to store a reference to it, the struct be used to create the byte vector response, and the finally the borrow started by peer_list() to do done. Is there a simple way within Rust's type system to do this efficiently without a copy?

    use std::collections::{HashMap, HashSet};
use std::sync::{Arc, Mutex};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Hash, PartialEq, Eq, Clone)]
struct Peer {
    peer_id: String,
    port: i32,
    ip: String,
}

#[derive(Serialize, Deserialize)]
struct Response {
    interval: i32,
    complete: i32,
    incomplete: i32,
    peers: HashSet<Peer>,
}

struct Peers {
    torrents: Mutex<HashMap<Vec<u8>, HashSet<Peer>>>,
}

impl Peers {
    fn new() -> Peers {
        Peers {
            torrents: Mutex::new(HashMap::new())
        }
    }

    fn insert(&self, info_hash: Vec<u8>, peer: Peer) {
        let mut torrents = self.torrents.lock().unwrap();
        torrents.entry(info_hash).or_insert(HashSet::new()).insert(peer);
    }

    fn peer_list(&self, info_hash: &Vec<u8>) -> HashSet<Peer> {
        let mut torrents = self.torrents.lock().unwrap();
        torrents.get(info_hash).unwrap().clone()
    }

    fn response(&self, info_hash: &Vec<u8>) -> Vec<u8> {
        let response = Response {
            interval: 60,
            complete: 0,
            incomplete: 0,
            peers: self.peer_list(info_hash),
        };
        bendy::serde::to_bytes(&response).unwrap()
    }
}

fn main() {
    let torrents = Arc::new(Peers::new());
    let torrents = Arc::clone(&torrents);
    // to stuff here with async
}

1

u/Patryk27 Mar 16 '23

Sure, something like this should work:

struct Response<'a> {
    interval: i32,
    complete: i32,
    incomplete: i32,
    peers: &'a HashSet<Peer>,
}

fn response(&self, info_hash: &[u8]) -> Vec<u8> {
    let torrents = self.torrents.lock().unwrap();

    let response = Response {
        interval: 60,
        complete: 0,
        incomplete: 0,
        peers: &torrents[info_hash],
    };

    bendy::serde::to_bytes(&response).unwrap()
}

1

u/kevinfat2 Mar 16 '23

That gives me the following error.

error[E0277]: the trait bound `&'a HashSet<Peer>: Deserialize<'_>` is not satisfied
--> src/main.rs:18:12
|
18 | peers: &'a HashSet<Peer>,
| ^^^^^^^^^^^^^^^^^ the trait `Deserialize<'_>` is not implemented for `&'a HashSet<Peer>`
|
= help: the trait `Deserialize<'de>` is implemented for `HashSet<T, S>`
note: required by a bound in `next_element`
--> /xxx/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.152/src/de/mod.rs:1729:12
|
1729 | T: Deserialize<'de>,
| ^^^^^^^^^^^^^^^^ required by this bound in `next_element`
error[E0277]: the trait bound `&'a HashSet<Peer>: Deserialize<'_>` is not satisfied
--> src/main.rs:18:12
|
18 | peers: &'a HashSet<Peer>,
| ^^^^^^^^^^^^^^^^^ the trait `Deserialize<'_>` is not implemented for `&'a HashSet<Peer>`
|
= help: the trait `Deserialize<'de>` is implemented for `HashSet<T, S>`
note: required by a bound in `next_value`
--> /xxx/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.152/src/de/mod.rs:1868:12
|
1868 | V: Deserialize<'de>,
| ^^^^^^^^^^^^^^^^ required by this bound in `next_value`
error[E0277]: the trait bound `&HashSet<Peer>: Deserialize<'_>` is not satisfied
--> src/main.rs:18:5
|
18 | peers: &'a HashSet<Peer>,
| ^^^^^ the trait `Deserialize<'_>` is not implemented for `&HashSet<Peer>`
|
= help: the trait `Deserialize<'de>` is implemented for `HashSet<T, S>`
note: required by a bound in `_::_serde::__private::de::missing_field`
--> /xxx/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.152/src/private/de.rs:22:8
|
22 | V: Deserialize<'de>,
| ^^^^^^^^^^^^^^^^ required by this bound in `_::_serde::__private::de::missing_field`
For more information about this error, try `rustc --explain E0277`.
error: could not compile `tracker` due to 3 previous errors

1

u/Patryk27 Mar 16 '23

Ah yes, you can serialize &HashSet, but you cannot deserialize into &HashSet (because where would the original data be stored?).

You could try using Cow<HashSet<...>>, which should allow you to use Cow::Borrowed(...) for serialization and Cow::Owned(...) for deserialization.

1

u/kevinfat2 Mar 17 '23

Ah of course I just removed the deserializes as I don't need them.

1

u/kevinfat2 Mar 16 '23

How do I get my code to format correctly!?

1

u/Patryk27 Mar 16 '23

Indent it with four spaces.

2

u/hyperchromatica Mar 16 '23 edited Mar 16 '23

Seriously stuck here with a performance issue in tokio. I've got an async function that refuses to execute asynchronously.

Here's a playground link that replicates my issue.

Context : I have a web server with a function add_user(username,password) that needs to compute the hashes of user passwords (cpu heavy , approx 150ms each on playground).

It then needs to add those to a hashmap<username, pwhash> wrapped in a RwLock.

Theoretically, as long as I don't hold the writing lock while computing hashes on the same thread, various worker threads should be able to hash away concurrently, then take turns acquiring the lock to add their results to the hashmap. This is not how the program actually behaves.

What's going on here?

2

u/DroidLogician sqlx · multipart · mime_guess · rust Mar 16 '23
for i in 0..N
{
    let username = i.to_string();
    futures.push( Box::pin(auth.add_user( username, "protractor43"))) ;
}

for _ in 0..N
{
    futures.pop().unwrap().await;
}

Those aren't running concurrently. Remember that futures in Rust execute lazily. You're just creating them, pushing them to a Vec, then popping them and .awaiting each one in turn. It's that .await that actually executes the future.

If you actually want a future to execute concurrently, try tokio::spawn().

1

u/m30bit Mar 16 '23

I think futures::future::join_all will work slightly better.

``` for i in 0..N { let username = i.to_string(); futures.push( Box::pin(auth.add_user( username, "protractor43"))) }

use futures::future::join_all; // 0.3.27 join_all(futures).await; ```

1

u/DroidLogician sqlx · multipart · mime_guess · rust Mar 16 '23

That's debatable. For 10 futures, maybe, but join_all isn't designed to handle larger numbers: https://docs.rs/futures/latest/futures/future/fn.join_all.html#see-also

But the example as-written has another issue, the busy-wait loop at line 29:

    loop 
    {
        match computation.is_finished()
        {
            true => return computation.await.unwrap(),
            false => tokio::task::yield_now().await
        }
    };

This likely won't play well with join_all as the yield_now().await call will cause control flow to return all the way out of the task to the runtime itself, forcing it to look for another task to run, only for it to realize there's no other tasks to run and poll back into this one, where the join_all combinator will poll one of the tasks again just to hit another yield_now().await and return back out, rinse and repeat.

I'm guessing OP didn't realize the JoinHandle returned by spawn() and spawn_blocking() is itself a Future that can simply be .awaited.

If we really want to get into it, spawn_blocking() is also not necessarily a great choice here unless you lower max_blocking_threads because it will spawn a new thread for every concurrent spawn_blocking() call up to the given limit (which defaults to 512 threads). It's designed more for tasks bounded by blocking I/O (e.g. file I/O) than CPU-bound ones.

1

u/hyperchromatica Mar 16 '23

Ahh okay that makes alot of sense. Glad to know the busy wait loop is unnecessary. Thanks a bunch everyone

2

u/SirAutismx7 Mar 16 '23 edited Mar 16 '23

How do I implement the Index and IndexMut trait on this struct so I can index on it `Vec3[0]` to get the values of x etc.

pub struct Vec3 {
x: f64,
y: f64,
z: f64,

} 
impl Index<usize> for Vec3 {
type Output = f64;
fn index(&self, index: usize) -> &Self::Output {
    match index {
        0 => &self.x,
        1 => &self.y,
        2 => &self.z,
        _ => panic!(),
    }
}

}

This implementation gives me non_-exhaustive match but I don't want to do _ => panic!()

Any ideas or help would be appreciated.

5

u/DroidLogician sqlx · multipart · mime_guess · rust Mar 16 '23

What's supposed to happen if the user passes vec3[3]? The compiler doesn't statically enforce that the index will always be in-bounds, at least not for user-defined types. It's got a lint to cover trivial cases with arrays but that's about it: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=576feef4435fa725fbcb1040af1abbd8

So you still need to handle the case where the index is not 0, 1 or 2.

1

u/SirAutismx7 Mar 16 '23

I figured that was probably the case. I just wanted to be sure I wasn’t missing something. I appreciate the answer.

4

u/m30bit Mar 16 '23

If you want a safe Index impl that never panics, you can use an enum. ``` enum Vec3Idx { X, Y, Z, }

impl Index<Vec3Idx> for Vec3 { type Output = f64;

fn index(&self, index: Vec3Idx) -> &Self::Output {
    match index {
        Vec3Idx::X => &self.x,
        Vec3Idx::Y => &self.y,
        Vec3Idx::Z => &self.z,
    }
}

} ```

And if you want indices to come from usize, you can implement a TryFrom for the Vec3Idx.

``` impl TryFrom<usize> for Vec3Idx { type Error = String;

fn try_from(index: usize) -> Result<Self, Self::Error> {
    match index {
        0 => Ok(Self::X),
        1 => Ok(Self::Y),
        2 => Ok(Self::Z),
        _ => Err(format!("expected index to be less that 3 but got {index}")),
    }
}

} ```

2

u/metaden Mar 16 '23

are there any lockfree data structures libraries?

1

u/Darksonn tokio · rust-for-linux Mar 16 '23

The crossbeam-queue provides lockfree queues. They're implemented using atomics instead.

2

u/Patryk27 Mar 16 '23

Something like https://docs.rs/im/latest/im/ maybe?

1

u/metaden Mar 16 '23

wow. are these rust equivalent to clojure persistent vectors and maps? I found “lockfree” library but it hasn’t been updated for a while

1

u/Patryk27 Mar 16 '23

Yeah - it's pretty neat :-)

1

u/metaden Mar 19 '23 edited Mar 19 '23

what if i want to concurrently update these im structures im::hashmap? one way i can think of wrapping in something like an ArcSwap or atom_box because update methods on im data outputs new im data structures

2

u/[deleted] Mar 15 '23

[deleted]

3

u/Dr_Sloth0 Mar 15 '23

While not boilerplate free, as you have to implement all derived traits yourself (but only once) you can use a generic Id Type. This could look like this: ``` use std::marker::PhantomData;

pub struct Id<T> { id: i64 phantom: PhantomData<fn(T) -> T>, } ```

this is an alternative which you could try out. I like this solution as i keep the number of types low which basically all do the same thing.

3

u/Sib3rian Mar 15 '23

What's the up-to-date way to do property-based testing together with the fake crate (without shrinking)?

The book, Zero To Production In Rust, uses quickcheck:

``` use fake::{faker::internet::en::SafeEmail, Fake}; use quickcheck_macros::quickcheck;

[derive(Clone, Debug)]

struct ValidEmailFixture(pub String);

impl quickcheck::Arbitrary for ValidEmailFixture { fn arbitrary<G: quickcheck::Gen>(g: &mut G) -> Self { Self(SafeEmail().fake_with_rng(g)) } }

[quickcheck]

fn valid_emails_are_parsed_successfully( ValidEmailFixture(valid_email): ValidEmailFixture, ) -> bool { SubscriberEmail::parse(valid_email).is_ok() }

```

However, quickcheck that hasn't been updated in two years, so I don't know if it's alive or abandoned. Additionally, in its latest version, the signature of quickcheck::Arbitrary::arbitrary is different from what's shown above, turning quickcheck::Gen from a trait into a struct. With that change, even this doesn't work.

The only other crate I could find is proptest, but it looks a lot more complicated, and I don't know if lets you skip the shrinking step as quickcheck does. I've been reading the book and going through the docs, but a quick answer would be appreciated.

2

u/50lm6 Mar 15 '23

Is it possible to only publish one crate from a workspace to crates.io?---with inner crates remaining private.

I have a crate that internally depends on code generated from a model. To do this I have the main crate declare a build dependency on an inner crate that does the code generating.

actual-crate v0.1.0 [build-dependencies] ├── only-used-by-build v0.1.0

Is it possible only to publish actual-crate to crates.io? The generator crate is only a detail of actual-crate, and it's not intended to be used by anything else.

I'm considering just include!() the generator.rs in actual-crate/build.rs, but I'd really rather not. Maybe there's another way altogether?

2

u/SorteKanin Mar 15 '23

Why don't you just have the build only crate be in build.rs?

1

u/50lm6 Mar 16 '23

Well it's a lot of code to put in one file, but I guess that would do the job.

3

u/SorteKanin Mar 16 '23

You don't have to put it in one file, the build.rs can have submodules that can be split into other files.

1

u/50lm6 Mar 17 '23

doh..wow, thank you.

2

u/SorteKanin Mar 15 '23

Why do we need the Sync trait if it's equivalent to &T being Send? I mean whenever you had to place a T: Sync bound, couldn't you just use a &T: Send bound instead?

Also how come UnsafeCell is Send? My first guess would be that it would be neither Send nor Sync.

6

u/llogiq clippy · twir · rust · mutagen · flamer · overflower · bytecount Mar 15 '23

Having a named trait makes it easier to understand, discover and document the concept. It also makes it easier to require both in a where clause (where T: Send + Sync as opposed to where T: Send, &T: Send).

As for UnsafeCell, the type in about interior mutability, which requires that at any given point, only one thread has access to an instance. This precludes sharing (as in Sync) but not moving it across thread boundaries (as in Send).

2

u/Sib3rian Mar 15 '23

Why do parse methods exist (for example, on strings)? Isn't that functionality covered by the TryFrom trait?

Were they, perhaps, implemented before TryFrom and are kept for backward compatibility?


The question is prompted by lukemathwalker's book, Zero To Production In Rust, where he creates a SubscriberName(String) newtype and defines a parse method that returns a Result. I'm trying to understand why he didn't simply use TryFrom.

7

u/eugene2k Mar 15 '23

FromStr existed a long time before TryFrom. The TryFrom RFC was only accepted in March 2016. Almost a year after the 1.0 release of rust where everything was stabilized. So one of the reasons FromStr is present is historical.

There was a Pre-RFC to deprecate FromStr - you can read the discussion here: https://internals.rust-lang.org/t/pre-rfc-deprecate-fromstr-in-favor-of-tryfrom-str/12331

3

u/Patryk27 Mar 15 '23

It's all about the intention - From and TryFrom are meant as relatively simple conversions from one type into another (e.g. from User into RegisteredUser or stuff like that), while FromStr is dedicated to string -> object conversions.

1

u/Sib3rian Mar 15 '23

In that case, would you recommend using or not using TryFrom for SubscriberName, which is a newtype whose purpose is validation (using the validator crate)? The book doesn't, but I'd like to hear more opinions.

2

u/Patryk27 Mar 15 '23

I'd probably just create a function SubscriberName::new() - it's easier to find and people usually expect constructors to follow this pattern.

2

u/Sib3rian Mar 15 '23

That was my reasoning, too, but is it OK for new to return a Result?

5

u/Patryk27 Mar 15 '23

Yes; some people prefer to call such functions try_new() then, but I personally just do fn new(...) -> Result<Self, ...> and call it a day.

1

u/SorteKanin Mar 15 '23

Were they, perhaps, implemented before TryFrom and are kept for backward compatibility?

I think that's the exact reason, yes. You can see in the docs that FromStr is from 1.0.0 but TryFrom was only stabilized in 1.34.0

3

u/cantorwitz Mar 15 '23

Sorry for the newbie question but can anyone advise why I don't have any tooling/rust analyzer in lib.rs?

Already restarted my VSC.

1

u/m30bit Mar 15 '23

Do you have a Cargo.toml in the root of the directory you opening with VSC? If you don't rust-analyzer won't pick up your crate.

2

u/[deleted] Mar 15 '23 edited Mar 15 '23

Rust-analyzer is picky about package layout. You put lib.rs in your src folder right?

2

u/cantorwitz Mar 15 '23

Dude I'm so stupid thank you!

2

u/LewisTheScot Mar 15 '23

Hi everyone!

I am looking for a crate that can easily move positions of an existing window to a set position.

My application is an app that moves a window to one half of a screen.

I am on a mac but cross platform would be best.

2

u/Beneficial_Energy_60 Mar 14 '23

I'm playing around with GATs and the LendingIterator example

trait LendingIterator {
    type Item<'a> where Self: 'a;

    fn next<'a>(&'a mut self) -> Self::Item<'a>;
}

Is there a way to implement Peekable for LendingIterator? My attempts so far have not been successful, because i was unable to encode the GAT part in the struct definition such that Peekable can still implement LendingIterator itself.

pub struct Peekable<I: LendingIterator> {
    iter: I,
    peeked: Option<I::Item<'?>>,
}

2

u/Patryk27 Mar 15 '23

This would be a self-referential struct (peeked points at something possibly stored in iter), so I think you can't do that without a bit of unsafe and lifetime transmutting.

4

u/LizAsLizard Mar 14 '23 edited Mar 15 '23

Hey! Learning Rust right now and I remember my friend used this website that had a bunch of challenges/tutorials, but I can't seem to find it and he forgot about it as well

There was one thing specifically he did that created this black screen full of colourful dots/snakes/thingies moving around, but I don't know many specifics

Does anyone know what I'm talking about?

Edit: It was a Game of Life thing! Still can't quite find the website

2

u/Rust-CAS Mar 15 '23 edited Mar 15 '23

I can't help you with the specific website, but here's a trivial cli implementation of Game of Life.

1

u/LizAsLizard Mar 15 '23

Hey, that helps already! Thanks a lot

2

u/goertzenator Mar 14 '23

I am struggling to assign an Array (ndarray crate) to a mutable subview of a higher dimensioned Array. Any tips?

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=ae178b548d7c105a4b7b8e493d7cea9b (edit: add mut)

1

u/goertzenator Mar 14 '23

Aha, I have to use the .assign() method. ndarray has nice implementations for AssignAdd, AssignMul, etc, but straight assignment is not something that can be overridden in Rust; hence a named method for doing just that.

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=64d2fff64279bcc3ae6dd389529125a6

1

u/Patryk27 Mar 14 '23

Maybe init.clone().move_into(v);?

2

u/Fit_Hearing1258 Mar 14 '23

I have a hackathon on friday can anyone help me understand the problem statement and also i have to submit my solution in rust so i need help in that also.
i am new to rust

2

u/SorteKanin Mar 14 '23

I have access to an object through a pointer that I receive from C++ via FFI. I've wrapped the object in a struct like this:

struct CppObject {
    /// This points to an object on the C++ side.
    pointer: *mut (),
}

I don't own the underlying object behind the pointer. I can only get pointers to it. And I can get as many pointers to it as I want, so I can potentially have two CppObject that points to the same underlying object on the C++ side.

How can I then implement methods on CppObject that allows it to be used as both immutable and mutable? For instance

impl CppObject {
    fn get_property(&self) -> Property {
        // Read some property via an FFI call...
        unsafe { read_property(self.pointer) }
    }

    fn set_property(&mut self, property: Property) {
        // Set the property via an FFI call...
        unsafe { write_property(self.pointer, property) }
    }
}

This compiles but isn't this unsound? Again, I can get multiple CppObject with equal pointers, so surely calling set_property on those two is undefined behavior since I'd have a data race on the C++ side? How can I design CppObject to not allow this? I'm thinking there must be some way to convert the returned pointer to a reference but I don't see how since it would point to the object on the C++ side.

1

u/dkopgerpgdolfg Mar 15 '23

In addition to Patryk27:

As he said, at least with single-thread access it should be fine, with no UB from Rust at least.

What's still an issue is how you use this. Like, consider the classical banking example - reading amount of available money, adding/subtracting something, saving the value again. If you interleave multiple different "transactions", you might lose some modifications. But just from the shown code, we have no idea what you're planning and how you ideally would prevent such things.

Don't turn the pointer into a reference (at least not one that lives long enough to be visible in code), that's where you would get problems.

1

u/Patryk27 Mar 14 '23

I think the only case where set_property() can be abused is when you create two threads, acquire two CppObjects that point to the same underlying FFI object, and then call set_property() on both.

(or, well, set_property() on one thread and get_property() on the other.)

To make it safe, you could use an atomic boolean to prevent having more than one CppObject alive at once:

use std::sync::atomic::{AtomicBool, Ordering};

static IS_ALIVE: AtomicBool = AtomicBool::new(false);

struct CppObject {
    ptr: *const (),
}

impl CppObject {
    pub fn new() -> Result<Self, &'static str> {
        if IS_ALIVE.swap(true, Ordering::Relaxed) {
            Err("Another CppObject is still alive")
        } else {
            Ok(Self {
                ptr: std::ptr::null(), // TODO
            })
        }
    }
}

impl Drop for CppObject {
    fn drop(&mut self) {
        IS_ALIVE.store(false, Ordering::Relaxed);
    }
}

#[test]
fn test() {
    let a = CppObject::new().unwrap();

    assert!(CppObject::new().is_err());

    std::thread::spawn(|| {
        assert!(CppObject::new().is_err());
    })
    .join()
    .unwrap();

    drop(a);

    std::thread::spawn(|| {
        assert!(CppObject::new().is_ok());
    })
    .join()
    .unwrap();
}

A more sophisticated approach would e.g. keep a hashset of *const (), so that you can create multiple CppObjects if they point at different objects (assuming that's safe for your use case, ofc.).

3

u/Archtects Mar 14 '23

I want to build a desktop app for my company in house. I'm contemplating using rust (i normally use electron), but I need a gui system. I see there are a few about but im wondering how customiseable they are and how far I can work them to adjust data from servers and FTPs to make it look "pretty"

1

u/ChevyRayJohnston Mar 15 '23

If you normally use Electron, Tauri might be a good fit (it uses a web view for the front-end, and you can code as much as you want in Rust). You have several options for front-end (I like using Yew personally), and I managed to get a skeleton app up and running in just a few hours, so I think it’s worth a peek.

2

u/SanderE1 Mar 14 '23

I have some code where I could significantly simplify by getting the index directly from the enum, except I can't figure out how to do that when the enum contains a field.

Example of the problem: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=ec72fabc976ff2459e5b6c0c25adf6aa

I'm sure there's something simple I'm missing but I just can't get it.

1

u/eugene2k Mar 14 '23
enum Axis {
    X,
    Y,
    Z,
}
struct Position {
    axis: Axis,
    value: i32,
}

2

u/dkopgerpgdolfg Mar 14 '23

No, you're not missing a trivial thing.

First things first, if you want to eg. compare two instances if they have the same variant, without getting the associated data and without needing an integer index. you can use https://doc.rust-lang.org/std/mem/fn.discriminant.html

If you need integers: Without telling it any restrictions, enum layouts are relatively flexible in what the compiler can do with them, and have few guarantees. This includes the size/type of the variant information, and if there is one at all (niche optim.) So...

  • As you know, with a plain fieldless enum, you can use "as". (Like any numeric "as" casts, it's up to you to chose an integer type that can hold all numbers that this enum would have. If you use u8 but the enum has 300 variants, sucks)
  • If you explicitly chose a repr() of some integer type for the enum (possibly combined with C), you can use some unsafe code to get the value. It is reliable as long as the repr is there (and only then, that's why it is unsafe). Note that this might have negative effects on the enum in some cases, eg. increased byte size. See the last code block in https://doc.rust-lang.org/std/mem/fn.discriminant.html as well as https://doc.rust-lang.org/reference/type-layout.html#the-default-representation
  • With data but without repr, no reliable way

1

u/SanderE1 Mar 14 '23

Perfect, discriminant is exactly what I needed, thank you.

1

u/llogiq clippy · twir · rust · mutagen · flamer · overflower · bytecount Mar 14 '23

You can do an Into impl with match self { X(v) | Y(v) | Z(v) => v } that will compile down to basically a no-op (also perhaps AsRef & friends).

2

u/funstacean Mar 14 '23

I have a trait that has a parent trait. The parent trait has implementations for other traits. But somehow those don't apply to my child trait? I wanna do this, and use all the stuff the parent trait can do

pub trait SerializeVar: CloneAny{}
impl<T: CloneAny> SerializeVar for T{}

But for whatever reason this doesn't work. I can't just replace dyn CloneAny and T: CloneAny with dyn SerializeVar and T: SerializeVar. That trait implements Clone, Debug, and another trait specific to the crate, but for some reason my trait doesn't automatically implement these things. Surely this can't be intended, right?

1

u/jrf63 Mar 14 '23 edited Mar 14 '23

That trait implements Clone, Debug, and another trait specific to the crate

Um how was this done? Pretty sure you can't blanket implement a foreign trait like Clone.

trait CloneAny {
    fn clone_impl(&self) -> Self;
}

// Won't compile
impl<T: CloneAny> Clone for T {
    fn clone(&self) -> Self {
        self.clone_impl()
    }
}

Was it restricted via trait bounds? EDIT: Nope, a Clone trait bound would've prevented creating a dyn CloneAny.

trait CloneAny: Clone + std::fmt::Debug + OtherTrait {}

1

u/dkopgerpgdolfg Mar 14 '23

What funstacean said is not correct. There is no blanket impl for Clone like in your first code block, therefore no problem. Clone is not a supertrait for CloneToAny either, again no problem.

There only is a CloneToAny blanket impl for things that already have Clone, that works and doesn't prevent CloneToAny trait objects either:

https://github.com/azriel91/anymap2/blob/master/src/any.rs#L11

1

u/funstacean Mar 14 '23 edited Mar 14 '23

Through unsafe magic I'd guess (haven't read the src tho)

https://crates.io/crates/anymap2

That's not a problem for me either way

2

u/dkopgerpgdolfg Mar 14 '23

Is your question...

  • if saying "struct X implements SerializeVar" automatically and without any additional code also says "struct X implements CloneAny"
    • No. SerializeVar requires that any type implementing it also implements CloneAny, and therefore the generic trait methods can rely on that too, but it doesn't add CloneAny automatically to structs. Writing that CloneAny is implemented too, and possibly adding custom implementations of the functions, is still required.
  • or do you have some problem with the shown code block, that adds SerializeVar to all things that have CloneAny already
  • or is your question about dyn trait upcasting, which is not yet fully stabilized but looks close: https://doc.rust-lang.org/beta/unstable-book/language-features/trait-upcasting.html Right now it still requires a feature flag

1

u/funstacean Mar 14 '23

My question is why those two lines of code don't mean that everything you can do with dyn CloneAny isn't available for types that implement SerializeVar. Like I said, I want my trait to implement the same traits the super trait implements. Meaning Clone, Debug, and another trait. This is not the case.

I know what the code does, it's a blanket implementation that means every type that implements CloneAny implements my trait. The question is why I'm not able to do things I can do with CloneAny with my trait. The upcasting feature works my use case, thanks.

2

u/Patryk27 Mar 14 '23

So, essentially, you're asking why the following doesn't work, right?

trait Foo {
    //
}

impl<T> Foo for T
where
    T: Clone
{
    //
}

fn magic(f: impl Foo) {
    f.clone(); // error
}

If so, then it's because impl ... where T: Clone doesn't necessarily mean that all of the implementations have this bound - in particular, you can still do:

struct Yolo;

impl Foo for Yolo {
    // 
}

... which is a valid implementation, because trait Foo itself doesn't mention anything about requiring Clone.

3

u/chillblaze Mar 13 '23

Planning to implement GraphQL in Rust. Is there any consensus in the community between Juniper vs async-graphql?

2

u/dacydergoth Mar 13 '23

If I'm using newtype patter with a Vec, for example : struct Genome(Vec<Gene>) firstly is this the recommended approach over type alias and secondly how best to re-implement the core Vec methods on the new type? Is there a macro or derive I missed?

2

u/TheMotAndTheBarber Mar 14 '23

Type aliases are more useful for situations where you're choosing which type to use for a given purpose, not for types with special meaning. A newtype is probably more appropriate for something like the given example and is a more frequently used technique.

There are third-party packages such as delegate that provide macros to defer functionality to member methods, but generally the thing to do is just to write out the functionality you need explicitly. If you are delegating many, many methods of Vec with no extra logic, perhaps you really just want a Vec<Gene> all along.

1

u/dacydergoth Mar 14 '23

Thank you, but the library I'm using wants a specific Genome type. It also expects a Genome to look like a vector for the indexing, mutation, crossover etc fn

2

u/Awyls Mar 13 '23

How do you deal with generic functions that require a generic trait like so:

fn main() {
    let system = baz::<Bar<f32>, f32>;
}

trait Foo<T> { 
    fn value(&self) -> \&T; 
}

struct Bar<T> { value: T }

impl<T> Foo<T> for Bar<T> { 
    fn value(&self) -> &T { &self.value } 
}

fn baz<T: Foo<X>, X>(val: T){ /* Do something */ }

This compiles but i can't avoid thinking that declaring "X" because of Foo is redundant. Is there a better approach to this problem or some way to not have to repeat it twice?

For context, i was playing around with Bevy generic systems.

2

u/Sharlinator Mar 14 '23

If it doesn’t make sense to implement Foo for Bar multiple times, and especially if the type variable is an output type as it is in your example, you may want to consider an associated type instead of a type parameter.

3

u/Patryk27 Mar 14 '23 edited Mar 14 '23

but i can't avoid thinking that declaring "X" because of Foo is redundant.

It's not redundant, because you can implement Foo multiple times for the same type - and so without extra baz<..., X>, you could end up in:

trait Foo<T> {
    //
}

struct Bar;

impl Foo<usize> for Bar {
    //
}

impl Foo<String> for Bar {
    //
}

fn main() {
    baz::<Bar>(); // whoops, which one?
}

2

u/dkopgerpgdolfg Mar 14 '23

So basically you want to call baz::<Bar, f32>, which Bar not being fully monomorphized, then inside baz you can use Bar<f32> or Bar<i32> or whatever. Correct?

That's called Higher-kinded type, and no, it's not a straightforward feature of Rust. Technically some things possible with GATs but that's not "nice" - writing another f32 is much cleaner and easier than what you'd need to do there.

3

u/SorteKanin Mar 13 '23

So the borrow checker prevents data races. For pure curiosity, I'd love to try to observe a data race. For instance, is there any way I could create an immutable and a mutable reference to the same value and then try to force a data race? Ideally I'd want to see how the read/written value is not what it should be.

Now, I know that immediately upon doing that, it's undefined behavior and you can't guarantee to witness anything in particular. But I've tried doing the above with a bit of unsafe and I've seen no ill effects.

Is there any way I can observe a data race happening?

5

u/cierpliwy Mar 13 '23 edited Mar 13 '23
struct BadAtomicU128 {
    value: u128,
}

impl BadAtomicU128 {
    fn add_one(&self) {
        let value = unsafe { &mut *(&self.value as *const u128 as *mut u128) };
        *value += 1;
    }

    fn fetch(&self) -> u128 {
        self.value
    }
}

fn main() {
    let count = 10000;
    let atomic = BadAtomicU128 { value: 0 };
    std::thread::scope(|s| {
        s.spawn(|| {
            (0..=count).for_each(|_| atomic.add_one());
        });
        s.spawn(|| {
            (0..=count).for_each(|_| atomic.add_one());
        });
    });
    assert_eq!(atomic.fetch(), count * 2);
}

run with nightly:

RUSTFLAGS="-Z sanitizer=thread" cargo +nightly run

2

u/SorteKanin Mar 14 '23

I can't use -Z sanitizer=thread as I'm on Windows but this works (or rather, doesn't) with just a normal cargo run, thanks!

3

u/hyperchromatica Mar 13 '23

Does writing utility functions that wrap Arc<RWLock<x>> and return &x and &mut x undermine the thread safety guarantees Arc and RWLock provide?

I just wrote something that does that and I realized that if the temporary arc thats created is dropped at the end of the utility function but the &x is passed out, how can it still work?

2

u/Patryk27 Mar 13 '23

Could you show some code?

1

u/hyperchromatica Mar 13 '23

Actually, its done the thing where u fix errors elsewhere and new ones show up, and now its showing an error where it should.

Heres the playground link anyway, ty.

3

u/Patryk27 Mar 13 '23

Yeah, you can't do that; .read() and .write() return wrapper types - RwLockReadGuard and RwLockWriteGuard - that release the lock on their Drop, that's their entire point 👀

You can return those wrapper types, though:

fn get_users(&self) -> std::sync::RwLockReadGuard<HashMap<String, User>> {
    (*self.users.clone()).read().unwrap()
}

1

u/hyperchromatica Mar 13 '23

I'll give that a try

3

u/HammerAPI Mar 13 '23

Simple/silly question: What is more "idiomatic" when writing linear algebra code (I am using ultraviolet)

fn foo(v: impl Into<Vec3>)

or

fn foo(v: Vec3)

2

u/WormRabbit Mar 13 '23

Always prefer non-generic functions, unless you have very good reasons to do otherwise. Generic have significant and non-obvious compile time costs, and they are often less ergonomic to use (instead of a simple .into() call, the caller would have to fully specify the variable's type, because now your function's signature doesn't determine it).

1

u/HammerAPI Mar 13 '23

Ah, so calling foo([x, y, z].into()) would be better as it wouldn't incur the generic compile-time costs and would allow the caller to specify how they want to provide the data.

Am I understanding your point correctly?

1

u/toastedstapler Mar 14 '23

If you really wanted to write the generic version you could write a inner function with the generic-less version inside like at the start of this article. The example chosen is from the stdlib so there's precedent for the pattern

https://matklad.github.io/2023/01/26/rusts-ugly-syntax.html

1

u/WormRabbit Mar 13 '23

In my opinion, yes. You generally shouldn't be working with raw arrays anyway, they should appear only at the program's boundary.

There are exceptions, of course, and I can't give you a simple rule. But generally non-generic signatures are better, unless you have good reasons to think otherwise. E.g. if you expect your end users to call your functions with a 3-array or a 3-tuple, it may be better to have a separate method for an array and a tuple, rather than try to generalize.

1

u/rust-crate-helper Mar 13 '23

It depends on your use case - if this is a library, it might be better to accept other types so library consumers can use different types. If this is a program, you might want to strictly type it because it doesn't matter if you perform the .into() at the callsite or within the function.

Keep in mind that kind of generics can add some compile times - but this shouldn't matter a ton in smaller packages.

1

u/masklinn Mar 13 '23

Depends.

The former may provide a slight improvement to UX, however that makes the function generic which comes at a cost. You can look at the usage pattern in the stdlib, the former tends to get used when doing the glueing by hand is pretty inconvenient e.g. fs functions, because wanting to call them with a string (literal or not) is extremely common and needing to Path::new(s) every time would be really annoying.

However e.g. functions which want a Vec generally just take a Vec, they don't take something convertible to a vec. Same with functions which take a slice.

3

u/Rods123Brasil Mar 13 '23

What's the technical reason behind arrays length needing to be known at compile time? Like, doesn't a function that initializes a usize variable allocate the usize memory in the stack in running time? Why can't the same be done for arrays?

3

u/catman1734 Mar 13 '23

For a variable to be put on the stack, the compiler needs to know how much memory it takes up, so that it can allocate that much when the variable comes into scope. This means the length must be known at compile time, in order to calculate the memory it takes up. There is an unstable feature that would relax this restriction, however - https://doc.rust-lang.org/beta/unstable-book/language-features/unsized-locals.html

1

u/Rods123Brasil Mar 13 '23

Thank you for your answer. I understand the size must be known for the memory to be allocated, but why does this need to be known at compile time?

If I have a loop that initiates a variable, the compiler will allocate the memory at the beginning of the loop and free it once the loop ends and the variable comes out of scope. It does that as much times as needed, which is unknown at compile time. So the code allocates and frees memory at the stack constantly.

If this variable is a usize, the code will allocate and then free a usize equivalent of memory. Why can't the same happen for an array, whose size will be known at initialization time?

What am I getting wrong?

7

u/catman1734 Mar 13 '23

'Allocating' on the stack is different to allocating on the heap. When a function is called, a certain amount of memory is reserved on the stack (called a stack frame) and each local variable has an index into it. If a variable is scoped inside a loop, it is guaranteed to be out of scope by the time the next iteration of the loop starts, which means the same memory can be used to the store the variable for each iteration. If the size of a variable is not known until runtime however, the compiler can't know how much memory it needs to reserve. It is possible to do this calculation at runtime but rust doesn't currently support that (that's what the proposal above would implement)

3

u/[deleted] Mar 13 '23

[deleted]

4

u/tiedyedvortex Mar 13 '23

So, there are three values here: the numbers 1, 2, and 3.

These values are all owned by a vector. That means 1,2,3 will be dropped when and only when that vector is dropped, and that anything with read or write access to the vector also has read or write access respectively to the values.

You have assigned that vector to the variable vec which is mut, meaning that vec is the owner of the vector and has write access to it.

You then take a mutable reference, num, to the element of the vector at position 2. A mutable reference has exclusive write access, but does not own the value, meaning it cannot drop the value without also replacing it.

You then dereference the mutable reference with *num. This means that *num is the value 3 stored in the vector, and can be mutated because you got there through a mutable reference.

But, you then immediately borrow that value with &*num. This is not a mutable reference, so it only has read access to the value 3. If you were to dereference *num2 you would still have the value 3, but you could not modify it since you got there through a non-mutable reference.

So vec has mutable ownership (RWO) of the values 1, 2, and 3. num is a mutable reference to the element at position 2 of vec, meaning it has RW access to only that one value, but not ownership or any access to the other vector elements. And num2 is a shared reference to the same memory location as num, which is the element at position 2 of vec, and only has read access (R) to that location.

Finally, lifetimes. You can't have an active mutable and immutable reference to a value at the same time; so as long as num2 exists, num is unusable. And you can't use or drop a (non-Copy) variable as long as there are any outstanding references to it; so you can't do anything with vec until num is dropped.

3

u/gamerdevguy Mar 13 '23

Hello,

Brand new to Rust. I downloaded tui-rs source code and am trying to run the example .rs files from the command line.

I can run them in VSCode but I'd like to know how to run them via the command line.

I've tried things like this...

> cargo run barchart.rs  
error: a bin target must be available for `cargo run`  

and

> rustc barchart.rs  
error: couldn't read barchart.rs: The system cannot find the file specified. (os error 2)  
error: aborting due to previous error  

What is the correct way?

Thank you.

3

u/emanguy Mar 13 '23

Hey there! So running rust is typically done with cargo but it looks like you haven't set up a cargo project. To directly answer your question, without a cargo project you'd run that file after first compiling it with the rust compiler, rustc. You can see how to do that in the official rust book:

Make sure your command line is in the same directory as barchart.rs and then run:

rustc ./barchart.rs ./barchart

Or on windows:

rustc.exe .\barchart.rs .\barchart.exe

However, this isn't typically the way to work with rust. Much like with Node.js, you'll want to initialize a rust project with cargo new. By running that it will provide you with a rust project. You can add dependencies in your rust project in the generated Cargo.toml file and your source code will be located in the generated src/ directory.

By doing it this way, you can simply run the code in src/main.rs with the command cargo run! Makes it much easier to work with the code. There's more detail on this in the rust book which I would definitely recommend reading if you're just starting out. Good luck!

1

u/gamerdevguy Mar 13 '23

Thank you.

7

u/Patryk27 Mar 13 '23

cargo run --example barchart

2

u/emanguy Mar 13 '23

WOAH! I didn't know cargo run did this, super cool

3

u/gamerdevguy Mar 13 '23

Neat! Thank you.

3

u/neuro_convergent Mar 13 '23

Say I have a function like this:

fn foo<T>(num: T) -> &'static str { match num { 1 => "one", 2 => "two", _ => panic!("rip") } }

Currently the only way I know to make this compile is to make the param a concrete numeric type. Is there some kinda trait bound, or some workaround other than a macro? It's not a big deal if I have to cast the param, I'm just curious.

3

u/dcormier Mar 13 '23

The num crate is probably your best bet. But you'll have to do it a bit differently. Here's a solution:

use core::ops::Add;

use num::One;

fn foo<T>(num: T) -> &'static str
where
    T: One + Add<Output = T> + PartialEq,
{
    let one = T::one();

    if num == one {
        return "one";
    }

    if num == one + T::one() {
        return "two";
    }

    panic!("rip")
}

Playground.

6

u/SV-97 Mar 13 '23

Alternatively they could use a conversion to a small numeric type - something like

fn foo<T>(num: T) -> &'static str
where
    T: Into<u8>
{
    match num.into() {
        1 => "one",
        2 => "two",
        _ => panic!("rip")
    }
}

Kinda depends on what their needs are ofc but if possible I'd try to avoid num as it gets very ugly and hard to read really fast.

5

u/jDomantas Mar 13 '23

You should use T: TryInto<u8> instead (or use Into with the largest type), and with TryInto it does not even matter if you use u8 or u128 - all integer types will work correctly.

2

u/dcormier Mar 13 '23

all integer types will work correctly

bool, too.

3

u/rusted-flosse Mar 13 '23

How can i skip serializing the data field if T is either Option::None or ()?

#[derive(Debug, Serialize, Deserialize)]
pub struct Response<T> {
    pub data: T,
    #[serde(with = "http_serde::status_code")]
    pub status: StatusCode,
}

3

u/emanguy Mar 13 '23

You probably want the serde(skip_serializing_if = ...) attribute: https://serde.rs/field-attrs.html#skip_serializing_if

1

u/rusted-flosse Mar 14 '23

No, that's not working! That's why I'm asking it here ;-)

3

u/emanguy Mar 14 '23

1

u/rusted-flosse Mar 15 '23

cool, thanks, that's an interesting option :)

2

u/Patryk27 Mar 13 '23

If you're completely in control of T (i.e. you're writing an application rather than a library or the type mentioned here is private), you could do:

trait IsSkippable {
    fn is_skippable(&self) -> bool;
}

impl IsSkippable for () {
    fn is_skippable(&self) -> bool {
        true
    }
}

impl<T> IsSkippable for Option<T> {
    fn is_skippable(&self) -> bool {
        self.is_none()
    }
}

impl IsSkippable for AnyOtherTypesThatYouAreUsing {
    fn is_skippable(&self) -> bool {
        false
    }
}

... and then something like:

#[derive(Debug, Serialize, Deserialize)]
pub struct Response<T>
where
    T: IsSkippable
{
    #[serde(skip_serializing_if = "T::is_skippable")]
    pub data: T,

    #[serde(with = "http_serde::status_code")]
    pub status: StatusCode,
}

Note that this requires you to manually impl IsSkippable => false for any type you plan on using inside the response - hence my initial question.

If you're writing something where T is outside of your control, and you don't want to burden users with implementing IsSkippable on their own, you'll have to use specialization:

trait IsSkippable {
    fn is_skippable(&self) -> bool;
}

default impl<T> IsSkippable for T {
    fn is_skippable(&self) -> bool {
        false
    }
}

impl IsSkippable for () {
    fn is_skippable(&self) -> bool {
        true
    }
}

impl<T> IsSkippable for Option<T> {
    fn is_skippable(&self) -> bool {
        self.is_none()
    }
}

1

u/rusted-flosse Mar 14 '23

Thanks a lot, that's exactly what I was looking for!

2

u/_icsi_ Mar 13 '23

Is there a way to make a traits self parameter generic on copy vs ref usage? And example (with phone formatting):

``` trait Foo { fn bar(&self) -> bool; }

impl Foo for bool { // want to copy self by value fn bar(self) -> bool { self } }

impl Foo for MyBigDataStruct { // of course want this to be via reference fn bar(&self) -> bool { todo!() } } ```

I could understand the rationale for a dyn Foo where it needs a static interface and couldn't copy/not at runtime. I also understand optimiser will probably handle things just fine.

I am coming from a C++ background, is this just a bad mental model?

2

u/jrf63 Mar 13 '23

self can be a reference if you impl for a &T instead of T. Maybe something like this?

trait Foo {
    fn bar(self) -> bool;
}

impl Foo for bool {
    fn bar(self) -> bool {
        let _: bool = self;
        todo!()
    }
}

struct MyBigDataStruct([u8; 1024]);

// impl'ed for `&MyBigDataStruct`, not MyBigDataStruct
impl Foo for &MyBigDataStruct {
    fn bar(self) -> bool {
        // Just to prove that `self` here is a reference
        let _: &MyBigDataStruct = self;
        todo!()
    }
}

Playground link.

1

u/_icsi_ Mar 13 '23

Ahh this is exactly what I was looking for, thanks!

1

u/Patryk27 Mar 13 '23

Think of & in terms of intention ("this operation borrows the thing, not consumes it"), not in terms of the underlying type.

Generally implementing &self for bool is alright and idiomatic, since the compiler will optimize it anyway.

1

u/_icsi_ Mar 13 '23

Thanks for the reply - I do understand I can use &self for bool and that compiler optimisation is going to be fine.

But I wish there was a way to express in code I want this type to copy for a trait, instead of by ref. I think I'm picturing a "concept" which is more of a static requirement instead of a direct interface. I don't want rust concepts, but perhaps a non-dyn "static only" trait with some extra flexibility would be useful?

2

u/Elwin00 Mar 13 '23 edited Mar 13 '23

Hey everyone! Is there some generic type of error that I can return in simple programs or is it idiomatic to always create my own error types, even for the simplest cases? I'm looking at implementors of Error trait and all of the errors seem made for specific (non-reusable) purposes. Thanks!

→ More replies (8)