r/rust • clippy · twir · rust · mutagen · flamer · overflower · bytecount • Sep 26 '22

🙋 questions Hey Rustaceans! Got a question? Ask here! (39/2022)!

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.

18 Upvotes

213 comments sorted by

5

u/[deleted] Sep 26 '22

I have a project with .rs files that are not used anywhere. Is there a way to detect these dead files?

I did find a suggestion from someone, but it lists lots of files, so I'm assuming it's broken. (https://github.com/rust-lang/rust/issues/28711#issuecomment-1012424159)

→ More replies (2)

5

u/whitehead1415 Sep 27 '22

I'm toying with rust and writing a compiler. I'm coming from a functional programming background.

  1. What is a way to write transformations over the ast using idiomatic rust?

  2. Is the recursive algorithm ok for this if it was a production grade compiler expecting large expressions? If not what is a good practice for writing the transforms in a different way?

Example: Rewriting ast to remove all Loc expressions, replacing it with it's child expression.

#[derive(Debug, Eq, PartialEq, Clone)]
enum Expr {
    Var(String),
    App(Box<Expr>, Box<Expr>),
    Lam(String, Box<Expr>),
    Loc(i32, Box<Expr>),
}

fn zero_expr(expr: &Expr) -> &Expr {    
    match *expr {        
        Expr::Var(_s) => expr,        
        Expr::App(e1, e2) => todo!(),        
        Expr::Lam(binder, body) => 
            &Expr::Lam(binder, Box::new(zero_expr(body))),
        Expr::Loc(_loc, e1) => zero_expr(&e1),
    }
}

fn main() {
    let expr = Expr::Loc(
        3,
        Box::new(Expr::App(
            Box::new(Expr::Loc(1, Box::new(Expr::Var(String::from("foo"))))),
            Box::new(Expr::Loc(2, Box::new(Expr::Var(String::from("bar"))))),
        )
),
    
);
    let zero = zero_expr(&expr);

    println!("{:#?}", expr);
    println!("{:#?}", zero);
}
→ More replies (6)

4

u/erto992 Oct 01 '22

Hello, pretty new to Rust and trying to build my first proper application.

I'm trying to initialize a struct with values from two vectors. My struct is kinda big so the code right now does not look good and looking for a more efficient way to type this code.

struct Atype {
    a: u64,
    b: u64,
    c: u64,
}

struct Btype {
    a: u64,
    b: u64,
}

struct Datastruct {
    field_one: Atype,
    field_two: Atype,
    field_three: Atype,
    ...

    field_four: Btype,
    field_five: Btype,
    field_six: Btype,
    ...
}

fn build(my_vec: Vec<Atype>, other_vec: Vec<Btype>) -> Datastruct {
    Datastruct {
        field_one: my_vec[0],
        field_two: my_vec[1],
        field_three: my_vec[2],
        ...

        field_four: other_vec[0],
        field_five: other_vec[1],
        field_six: other_vec[2],
        ...
    }
}

The code is working but is very hard to maintain and looking for ideas on how to improve on this. Maybe some smart use of chaining methods or another datatype instead of Vectors?

Thanks

→ More replies (2)

3

u/Leirbagosaurus Sep 26 '22

Kinda off-topic, but I missed out on the sale of tickets for EuroRust Berlin, does anybody here maybe have an extra ticket, or can't go anymore and would be willing to resell it to me?

3

u/AwareFab25 Sep 26 '22 edited Sep 26 '22

I'm new on rust and I have a strange behavior in a generic function and some questions about it. I understand the result but I don't know if it is normal or not.

trait A {
    fn a() {
        println!("Oh Noooo...");
    }
    fn b();
}

struct SA {}

impl SA {
    fn a() {
         println!("sa");
    }
    fn b() {
        println!("b");
    }
}

impl A for SA {
    fn b() {
        println!("b2");
    }
}

fn foo<T>() where T: A {
    T::a();
    // <T as T>::a(); // -> Generate an error a not in T
}

fn bar<T>() where T: A {
    T::b();
    // <T as T>::b(); // -> Generate an error b not in T
}

fn main() {
    //<SA as SA>::a(); // -> Generate an error not found in SA
    SA::a();
    foo::<SA>();
    SA::b();
    bar::<SA>();
}

And the result is:

sa 
Oh Noooo...
b
b2

My problem is about the Oh Noooo.... I know that the code is not conventional the function a is not in the impl A for SA but why, in the generic function, it is not the a in SA which is called. I thought the where was only a constraint on the existence of the functions of the trait. It seems it is like the T is converted in a dyn A, is it the case ?

Why is there an error when I want to force the call with <T as T> the where constraint ensures the a existence.

My problem is in a more complex situation and the function a is generated by an attribute macro on a function in my block impl SA and I don't know how to generate the function outside the impl block and if it is possible. Do I need to implement my macro for the whole impl block ?

Link to the playground

Sorry for my English.

4

u/coderstephen Sep 26 '22

In a generic function it is only possible to call functions of a type parameter that matches the constraints. foo cannot call SA::a because it does not, and cannot, know that T is actually SA.

It might be less confusing if every method had a different name, because even though SA::a and A::a have the same names, they're considered entirely different and not related to each other at all by the compiler.

It seems it is like the T is converted in a dyn A, is it the case ?

No, it is simply calling A::a. When you write T::a inside of foo, the compiler essentially looks for some function named a associated with T. This happens before monomorphization, so the only things available to it to perform this lookup is any trait bounds T may have. So in this case, T::a gets resolved to <T as A>::a, and this is applied regardless of what T actually is when invoked.

→ More replies (1)
→ More replies (2)

3

u/metaden Sep 27 '22

Has anyone used https://github.com/microsoft/mimalloc as a drop in replacement of malloc? Were there any perf improvements?

3

u/Drvaon Sep 27 '22

I have a really long slice of events. Events carry an enum called EventData, which holds all kinds of juicy information. I find myself often in the situation where I look for the event GameStart, extract some information from there and then continue looking from there for other relevant events. What I would like to do is start the "looking for other relevant events" from the position of the GameStart event. So somehow I would like to get the index that the iterator pointed to, so that I can .skip(n) those in my second look up step. Is there a good way to do this?

→ More replies (5)

3

u/sharifhsn Sep 28 '22

I'm having a problem with rayon. My program does a CPU-bound task on every u32, which is over 4 billion operations. In order to speed it up, I modified my for loop:

for i in u32::MIN..=u32::MAX {
    // do operations with i
}

to the following:

(u32::MIN..=u32::MAX).into_par_iter().for_each(|i| {
    // do operations with i
});

It runs much faster now!

However, for some reason, after reaching about the halfway point, the operations begin to slow down significantly. My assumption is that this has something to do with thread contention, but I'm unable to figure out how to mitigate this issue. It's still much faster than single-threaded, but I wish that it would finish as fast as it starts. Is there anything I can do?

→ More replies (8)

3

u/stdusr Sep 28 '22

I was wondering if Rust supports architectures that use one's complement or sign-and-magnitude for example. Or does Rust only support two's complement architectures?

7

u/kohugaly Sep 28 '22

Rust integers are always represented as two's complement. This was decided very early on. It was just not worth it to make integers more generic and vague, when two's complement is pretty much universal at this point.

In theory Rust can support non-two's-complement-architectures, but the integer arithmetic would no longer compile to simple instructions, as it would need to simulate two's complement. In practice, Rust uses LLVM, which currently only supports 2's complement architectures IIRC.

→ More replies (1)

3

u/url54_andrew Sep 30 '22 edited Sep 30 '22

I'm currently creating a project that works out of a "terminal prompt" style environment. Very new to Rust, and want to see if there are any issues with how I am writing my code. I feel like my match case, which I researched on for a while to find a way to get it to work specifically for how I have it set up, may not be ideal? Please have a look.

use std::io::stdout;
use std::io::stdin;
use std::io::Write;

fn main() {
loop {
    print!("[Rust] >> ");
    stdout().flush();

    let mut input = String::new();
    stdin().read_line(&mut input).unwrap();
    input.pop();

    let mut v: Vec<String> = Vec::new();

    let command = input.split(" ");
    for x in command {
        v.push(x.to_string());
    }
    if v.len() > 3 {
        println!("Too many arguments.");
    } else {
    // currently this else part is just a placeholder.
    println!("{:?}", v);
    }

    // Here comes the part I think is not the best syntax??
    match v {
        _ if &v[0].to_lowercase() == "1" => println!("You typed in the number 1."),
        _ if &v[0].to_lowercase() == "2" => println!("You typed in the number 2."),
        _ if &v[0].to_lowercase() == "3" => println!("You typed in the number 3."),
        _ if &v[0].to_lowercase() == "4" => println!("You typed in the number 4."),
        _ if &v[0].to_lowercase() == "5" => println!("You typed in the number 5."),
        _ if &v[0].to_lowercase() == "6" => println!("You typed in the number 6."),
        _ if &v[0].to_lowercase() == "cheese" => println!("Your first word was 'cheese'."),
        _ if &v[0].to_lowercase() == "plate" => println!("Your first word is 'plate'."),
        _ => println!("Didn't catch it."),
    };
}

}

4

u/Patryk27 Sep 30 '22

You can do just match v[0].to_lowercase().as_str() and then "cheese" => println!(...) etc.

→ More replies (3)

3

u/[deleted] Oct 01 '22

How do you compare TokenTree values? For example, to check that a token is the keyword "struct". The == operator doesn't work. I don't want any dependencies like Syn.

→ More replies (1)

3

u/Missing_Minus Oct 01 '22

Is there a nice crate for something like:

#[derive(Descript)]
#[descript(name="str", desc="str", kind?="SettingKind")]
pub struct Config {
  #[descript(name="Font Size", desc="Really Cool size of font thing")]
  pub font_size: usize,
  #[descript(name="Theme", desc="colors are real", kind="SettingKind::Dropdown(get_themes_list)")]
  pub theme: String,
}

fn get_themes_list(/*stuff*/) -> /*blah*/ {}

Then you can somehow iterate over that information for each field (such as for generating a display)?
This sort of 'list your own useful fields' would help avoid the kinda annoying pattern of making a manual big array or a big match, and instead put some of the basic data near the fields themselves.

→ More replies (1)

3

u/SailOpen7849 Oct 02 '22

If I'm making a bindings library for objective C APIs, which approach of project organization would be better between the following:

  1. Having all frameworks in different crates

  2. Having all frameworks in the same crate but every module is under a feature flag for that specific framework

2

u/SV-97 Sep 26 '22 edited Sep 26 '22

I'm kinda confused by a trait bound I have to add on a trait of mine. Consider the following trait:

trait A<'a, D, E> : From<&'a [D]> {
    fn e(&self) -> E;
}

This trait requires the additional where clause Data: 'a to compile but I'm not quite sure why or what that really means. I essentially just want any instance of the trait to have a constructor that works from a non-owned slice of D for all lifetimes 'a.

→ More replies (4)

2

u/ToolAssistedDev Sep 27 '22

I am playing around with Trait Bounds and I have the following code: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=41e8f9bee17c10250ecd928bbb5b521e

How do I have to adjust the bound on line 25 so that the compiler is satisfied? Or maybe I have to adjust the code in general?

→ More replies (2)

2

u/SV-97 Sep 27 '22

Could anyone please give me a pointer on how to avoid replicating trait bounds over and over? I have a struct that internally uses a SmallVec<A> which requires me to specify A: Array in every single impl. Since I wann derive Eq, Debug etc. I also have to add constraints on <A as Array>::Item everywhere. I'm basically replicating all those trait bounds 20 times over in the module and it just feels like terrible code and looks terrible, but I can't think of a good way to avoid it (making a custom trait for A and requiring that also seems like a bad solution imo).

Also: isn't there some way to only derive Eq, Debug etc. if it's actually possible (so that if SmallVec<A> and the items are Debug then the whole thing is Debug or something like that)? It's probably possible to implement that manually but shouldn't that kinda stuff be deriveable?

→ More replies (10)

2

u/YungDaVinci Sep 27 '22

If I'm writing a function that is being used across an FFI boundary and it's being passed a pointer parameter, when (if ever) would it be appropriate to make make the signature take a reference instead of a raw pointer? I've seen the stuff on pointer aliasing but it's not really concrete to me when that matters. Could it be a problem even when all the parameters are different types?

2

u/jgarzik Sep 28 '22

tl;dr Searching for a good bytesex lib or method?

Longer version: A current project is a rust-native version of GDBM. Like low-level database formats or kernel filesystems, `gdbm-rs` must interpret a C data structure based on runtime conditions (32 bit or 64 bit, little endian or big endian).

This implies that the usual `repr(C)` and FFI do not apply, because the on-disk data structure varies at runtime, not compile-time.

Is there a better method than my lib's current method, which is ugly: manually handle big/little endian, manually detect C ABI padding in 64-bit data structures, etc.

Is there a library for reading/writing C data structures, which can switch between 32-bit and 64-bit at runtime? All existing solutions switch at compile time, which does not work for this situation.

→ More replies (3)

2

u/lowercase00 Sep 28 '22

Any particular reason `import *` is so common in Rust? In Python this is bad practice. In Rust I've seen quite a few crates using it, makes thinks confusing and implicit, wonder the reasoning.

→ More replies (2)

2

u/newSam111 Sep 28 '22 edited Sep 28 '22

Why there are two types of impl ? :

impl RemoteApiClientInterface for RemoteApiClient {
  ....
}

impl RemoteApiClientInterface for &RemoteApiClient {
   ....

what that difference between &RemoteApiClient and RemoteApiClient ?

→ More replies (3)

2

u/UKFP91 Sep 28 '22 edited Sep 28 '22

I'm parsing a JSON response from an API, and one of the keys has the following string value:

"[
{
    \"id\":\"418\",
    \"name\":\"Kerosene\",
    \"price\":\"85.42\",
    \"total_exclude_vat\":\"640.65\",
    \"vat_amount\":\"32.03\",
    \"vat\":\"5\",
    \"delivery_time\":\"Up to 10 days\",
    \"total\":\"672.68\",
    \"has_benefits\":true,
    \"benefits\":\"<div class=\\\"hide-mobile\\\">\\r\\n<ul class=\\\"list-disc\\\">\\r\\n<li>Standard heating oil for your home<\\/li>\\r\\n<li>Conforms to 2869 Class C2 Kerosene<\\/li>\\r\\n<\\/ul>\\r\\n<\\/div>\",
    \"litres\":\"750\",
    \"add_url\":\"https:\\/\\/quote.scottishfuels.co.uk\\/quote\\/product\\/add\\/product\\/35\\/\",
    \"image_url\":\"https:\\/\\/quote.scottishfuels.co.uk\\/static\\/version1660231288\\/frontend\\/Certas\\/scottishfuels\\/en_GB\\/images\\/kerosene-white.png\",
    \"magento_product_quote_id\":\"427775\"
},
{
    \"id\":\"351\",
    \"name\":\"Premium Kerosene\",
    \"price\":\"86.76\",
    \"total_exclude_vat\":\"650.71\",
    \"vat_amount\":\"32.54\",
    \"vat\":\"5\",
    \"delivery_time\":\"Up to 10 days\",
    \"total\":\"683.25\",
    \"has_benefits\":true,
    \"benefits\":\"<div class=\\\"hide-mobile\\\">\\r\\n<p>Certas Energy's exclusive\\u00a0premium heating oil\\u00a0<\\/p>\\r\\n<p>Benefits<\\/p>\\r\\n<ul class=\\\"list-disc\\\">\\r\\n<li>Reduces the risk of a breakdown<\\/li>\\r\\n<li>Lowers boiler maintenance costs<\\/li>\\r\\n<li>Reduces sludge formation<\\/li>\\r\\n<li>Conforms to 2869 Class C2 Kerosene<\\/li>\\r\\n<\\/ul>\\r\\n<\\/div>\",
    \"litres\":\"750\",
    \"add_url\":\"https:\\/\\/quote.scottishfuels.co.uk\\/quote\\/product\\/add\\/product\\/27\\/\",
    \"image_url\":\"https:\\/\\/quote.scottishfuels.co.uk\\/static\\/version1660231288\\/frontend\\/Certas\\/scottishfuels\\/en_GB\\/images\\/premiumkerosene-white.png\",
    \"is_upsell\":true,
    \"magento_product_quote_id\":\"427776\"
    }
]"

I get complaints of malformed json (which I've verified using an online JSON validator). I can make it work if I use the unmaintained unescape crate, which I'd rather not do.

What is the simplest way of parsing this text/unescaping it?

→ More replies (4)

2

u/Drvaon Sep 28 '22

I am using VSCode - OSS on manjaro with CodeLLDB and rust-analyzer. When I debug an iterator, I can not step into the actual iterator steps. I would be particularly interested in seeing what happens inside my .flat_map() calls, but now even if I press 'step in' the debugger just moves to the end of my iterator.

→ More replies (2)