These are chat archives for rust-lang/rust

4th
Dec 2018
Ali Shirvani
@alishir
Dec 04 2018 04:38
is it possible to limit number of cpu that used by cargo during cargo build?
matrixbot
@matrixbot
Dec 04 2018 04:39
bspeice cargo build -j N should be what you want, no?
Ali Shirvani
@alishir
Dec 04 2018 04:39
thanks a lot
Zakarum
@omni-viral
Dec 04 2018 10:24
@vmalloc Not sure but you are probabyl fixing what isn't too broken. In release unnecessary allocation could be easily optimized away
Tim Robinson
@1tgr
Dec 04 2018 10:28
The compiler is smart, but I’ve never seen it smart enough to eliminate a memory allocation in this way
Zakarum
@omni-viral
Dec 04 2018 10:44
Hmmm. call <alloc::string::String as core::convert::From<&'a str>>::from@PLT is not get inlined with opt-level=3. After that compiler can't possibly optimize out allocation
If it would plain
string = malloc(N);
memcpy(string, str, N);
if (strcmp(string, "qwe") == 0) {    
   free(string);
}
Then I hope comparison would be performed over str and allocation would be moved after comparison fail
Ali Shirvani
@alishir
Dec 04 2018 11:02
How can I create string fromlet a = b"helloword"?
Tim Robinson
@1tgr
Dec 04 2018 11:03
String, or str?
Ali Shirvani
@alishir
Dec 04 2018 11:03
String
I tried from_utf8 but it requires Vec
Tim Robinson
@1tgr
Dec 04 2018 11:03
let s = str::from_utf8(a).unwrap().to_owned();
Yep, you either go via str or via Vec
Ali Shirvani
@alishir
Dec 04 2018 11:04
I got it, thanks a lot
Nikolay Denev
@ndenev
Dec 04 2018 11:19

I found a bug in my code that for some weird reason used to work and I have no idea why. So I had this code (yeah, I know, too much clone()-ing going on), and the code within or_insert() never got executed unless the entry was missing.

                threads.entry(node.clone()).or_insert({
                    info!("Starting pinger thread for {:?}", node);
                    probes::ping::Pinger::new(metrics.clone(), &node)
                });

Later I've changed a few things, updated to 1.30.1, moved this code into a thread (it was running in the main thread before), and it started leaking these threads, as it got executed every time regardless if the entry was present in the map or not.
Ultimately I fixed this by calling the proper or_insert_with(), but still, I have no idea how it was working before. Any ideas?

red75prime
@red75prime
Dec 04 2018 11:25

Maybe a bug in PartialEq implementation for node.

It is required that the keys implement the Eq and Hash traits, although this can frequently be achieved by using #[derive(PartialEq, Eq, Hash)]. If you implement these yourself, it is important that the following property holds:

k1 == k2 -> hash(k1) == hash(k2)
red75prime
@red75prime
Dec 04 2018 11:31
Or key is changed after it is inserted into threads. Does it contain Arc<Mutex<_>> or something with interior mutability?
Nikolay Denev
@ndenev
Dec 04 2018 11:36
hmm, the PartialEq for Node is auto derived
And after inserting to threads it is not being modified. It's a Vec<Node> that I iterate over, and every "cycle" I get a new list, so the Vec itself goes out of scope, so the hashmap should have the only reference
Tim Robinson
@1tgr
Dec 04 2018 12:35
That code definitely calls Pinger::new every time, unless there's a bug in the compiler or threads.entry(node.clone()) panics
It's equivalent to
info!("Starting pinger thread for {:?}", node);
let thread = probes::ping::Pinger::new(metrics.clone(), &node);
threads.entry(node.clone()).or_insert(thread);
(but you knew that)
Ash
@ashthespy
Dec 04 2018 12:52
How does rust decide what isize should be?
Tim Robinson
@1tgr
Dec 04 2018 13:02
It's defined specifically on each target
Via the target JSON file
You can ask rustc to describe the current target using
cargo +nightly rustc -- --print target-spec-json -Z unstable-options
I think the isize assumption is part of the data-layout field
Or target-pointer-width, not sure
It's decided based on target-pointer-width https://doc.rust-lang.org/src/core/num/mod.rs.html#2300
Ash
@ashthespy
Dec 04 2018 14:04
@1tgr do you know if this is decided based on what WORD_BIT should be?
The reason I ask is - using a c wrapper lib that uses c_long - and wondering how to maintain both 32 and 64 bit compatibility with the same codebase.
Denis Lisov
@tanriol
Dec 04 2018 14:05
What's the problem with compatibility?
Ash
@ashthespy
Dec 04 2018 14:07
The library diwic/alsa-rs#41 uses i64 which when c_long is only 32bits leads to issues
so was wondering if replacing the explicit i64 with isize was the way to go?
trsh
@trsh
Dec 04 2018 14:37
"This type will always be i32 or i64. Most notably, many Linux-based systems assume an i64, but Windows assumes i32"
Anyway when converting to c_long it will take i32 on windows
U can for now force cast to i32 and panick if fails?
Denis Lisov
@tanriol
Dec 04 2018 14:43
What are these values mapped to? 0 = no sound, (max) = 100%, negative invalid?
Ash
@ashthespy
Dec 04 2018 14:44
@tanriol yep something like that usually. But it's alsa in the end, so I am not 100% sure of all cases
Denis Lisov
@tanriol
Dec 04 2018 14:47
If I were building a high-level (user-level) API for this kind of controls, I'd probably use f64 for volume and map it to whatever range is expected on this platform.
Ash
@ashthespy
Dec 04 2018 15:02
@tanriol that is what I am doing currently - mapping a f64 based on the actual range of the device.
But I am stuck at making it work with both 64/32 bit proof:
For example I have this for 32bit
 let vol_db = i64::from((self.pvol(vol, 0x0000, 0xFFFF).log10() * 6000.0).floor() as i32)
                    + self.params.max_db.0;
But want replace the i64::from( vol as i32) part with something platform (32/64 bit) agnostic
Tim Robinson
@1tgr
Dec 04 2018 15:40
I don’t think this is something you would want to vary across 32/64 bit
Either the volume spans a 32 bit range, or a 64 bit range
The size of a pointer shouldn’t affect that... 32 bit systems can do 64 bit arithmetic too
Ash
@ashthespy
Dec 04 2018 15:48
I might not be following you completely.
Wouldn't the underlying value (so the volume range in this case) that is c_long be 32/64 bit specific? So the rational being that if the system uses 32bit pointers, c_long would also be 32bits?
i.e the length of WORD_BIT
Ichoran
@Ichoran
Dec 04 2018 16:14
@ashthespy - Matching the word size of the target platform is really annoying, and a lot of "32-bit" processors directly support 64-bit floats anyway. You should only do it if you really, really need to for performance.
Otherwise, if you need 64 bits for accuracy, use 64 bits everywhere.
Ash
@ashthespy
Dec 04 2018 16:16
The issue is that I am using the underlying alsa-lib C interface - so if I don't match the word size of the underlying c_long I run into issues..
Ichoran
@Ichoran
Dec 04 2018 16:16
That's what usize is for.
(Or isize if you need it to be signed.)
But you don't need a floating point value to match that size, do you?
Ash
@ashthespy
Dec 04 2018 16:17
right - so that was my suggestion as well - but doubt were raised if isize would always be the same as c_long
Ichoran
@Ichoran
Dec 04 2018 16:20
You can't guarantee much of anything with long in C, not even from compiler to compiler on the same machine. It's no smaller than a short or int; that's about all you're promised.
Ash
@ashthespy
Dec 04 2018 16:20
fair enough!
Ichoran
@Ichoran
Dec 04 2018 16:21
So I'd expect either (1) isize always works, or (2) c_long doesn't even agree with C compilers.
Tim Robinson
@1tgr
Dec 04 2018 16:22
On the C side you're stuck with c_long unfortunately
At least on the Rust side you have the opportunity to expose it consistently
i64 would support a c_long on any platform targetted by Rust; on 32-bit platforms you could have value >> 32 as c_long, and value as c_long on 64 bits
Or do it with 0.0 <= f64 < 1.0 and map to c_long as appropriate
Ash
@ashthespy
Dec 04 2018 16:26
Hmm - so many questions now :-D
Tim Robinson
@1tgr
Dec 04 2018 16:26
Or if you want to keep fidelity with the underling ALSA lib, expose c_long on the Rust side and have the user deal with it
Ash
@ashthespy
Dec 04 2018 16:27
I still wonder if this is a issue for the rust C wrapper to handle - or offloaded to my code that uses this wrapper.
given that the wrapper exposed an i64 it took a while before I figured out that the underlying c_long was only 32bits . So now that I know this, it should be fine to do my math with an let myval:isize and then call the wrapper with myval as i64
Tim Robinson
@1tgr
Dec 04 2018 16:33
Do the math on an i64, if you're going to cast it to i64 when you call the wrapper
Ichoran
@Ichoran
Dec 04 2018 16:33
You also could stick something in that would fail to compile if the two ever get out of sync. You can get a constant equal to the size by calling std::mem::size_of::<isize>() and likewise for c_long
Tim Robinson
@1tgr
Dec 04 2018 16:33
Or do you want to do 32-bit math on a 32-bit platform, then smuggle it inside an i64 (with the top bits set to zero) so it can go to the API as a c_long?
Ichoran
@Ichoran
Dec 04 2018 16:34
Unless performance is critical, I'd do the math with the same amount of space always (i64 in this case, I guess)
I rather suspect that if you're calling audio libs, doing a little 64-bit math on a 32 bit platform is not going to be the bottleneck.
Ash
@ashthespy
Dec 04 2018 16:36
From my understanding : i64::max() > LONG_MAX (for 32bit) - so when I do my math with i64 and pass it along its trying to map a 64 bit range to 32bit range?
or am I complicating this for no reason?
Ichoran
@Ichoran
Dec 04 2018 16:43
What do the values represent?
Are they all, say, going to be between 0 and 1000 regardless?
Tim Robinson
@1tgr
Dec 04 2018 16:53
In an API like snd_mixer_selem_set_playback_volume_all, where is the meaning of the C long defined?
Wondering what people do when they use this interface directly
Ichoran
@Ichoran
Dec 04 2018 18:12
It is a c_long, but how do you know what the values correspond to?
You have to query it and it will tell you what the valid range is.
I would just map it onto 0-1--a f32 should be plenty, as people can't tell a millionth increment in volume--and map into that range as the last step, internally in your library. No real reason to expose the API user to it.
Ash
@ashthespy
Dec 04 2018 18:17

hmm, this is actually what I do. I need to recheck why it was failing with I wasn't casting it as i32.

Thanks for all your inputs, back to debugging :-)

Ichoran
@Ichoran
Dec 04 2018 18:18
Maybe you're doing the math in the wrong order?
For instance (vol as i32)*(max_vol - min_vol) + min_vol looks like it would work, but it doesn't.
Instead, you need to do the multiplication in floating point (hopefully min_vol is zero or positive): ((vol * ((max_vol - min_vol) as f32)).round() as i32) + min_vol
Tritone
@tritone11
Dec 04 2018 19:09
Hello, I am new to Rust and I cannot get around about managing errors
I have a loop and sometimes it panics on an unwrap, I wish to go to the next loop when it happens
Nopey Nope
@Nopey
Dec 04 2018 19:10
try using an if statement to match the Option/Error
loop{
    //Some(...) is an Option<...>, Ok(...) is an Error<...>
    if let Some(val) = thing_youre_unwrapping{
        //Do things with val
    }
}
Tritone
@tritone11
Dec 04 2018 19:12
many thanks, I am trying
Paul Hauner
@paulhauner
Dec 04 2018 23:14

Hey, I have a question about containing variables inside small scopes defined by curly braces. I've written a playground gist here that has option_a() and an option_b() functions to compare.

My question is: option_b() is "nice" in the sense that I have isolated the scope of my variables, it's very clear to the reader (and compiler) that is_larger is never used again later in the function. However, I am interested as to whether there are any downsides to this approach that I cannot immediately see, e.g., performance hits or quirks. I tried searching online but I found the topic difficult to search for.

(PS. I know this example could be refactored into something more elegant -- I have written it like this to demonstrate my question.)

Thank you for your time

Ichoran
@Ichoran
Dec 04 2018 23:27
I don't see much advantage in option_b() if you are just testing conditions to do an early exit. Rust will keep you safe from most mistakes should you just have everything in one scope like in option_a().
However, if those blocks are hiding nuisance variables as part of an assignment to some variable that you want to use later on, then I think it's a good idea.
As far as performance goes, with NLL there shouldn't be any difference. Pre-NLL, the local blocks might trigger some cleanup earlier than otherwise, but the performance consequences of that are difficult to predict (and probably would be modest, and might not matter after the optimizer gets done with it).
Anyway, the point is that while it is very clear that is_larger isn't used again, it probably doesn't matter very much that it isn't used again.
But, anyway, it's fine to use it if it's helping you keep straight things that otherwise might trip you up.
(There's always a minor readability penalty for having things too deeply indented, so the default bias should be to not indent extra if all else is equal. Doesn't take much to tip the balance, though.)
Denis Lisov
@tanriol
Dec 04 2018 23:35
It may make sense to isolate separate parts of logic not into nested blocks, but into separate functions (methods).
@Ichoran Are you sure about NLL? AFAIK, NLL only accepts more code (and rejects some buggy one), but it does not change what happens during code execution.
Ichoran
@Ichoran
Dec 04 2018 23:37
Hm, maybe you're right. It could in principle drop things early, but I guess it still follows lexical rules for that.
I had vaguely remembered some discussion about it, but maybe I misremembered what the conclusion was.