These are chat archives for rust-lang/rust

15th
May 2017
David McGillicuddy
@djmcgill
May 15 2017 12:15

Has anybody used compilter_builtins before?
I have a crate, dummy, that contains:

#![feature(compiler_builtins_lib)]
#![no_std]

extern crate compiler_builtins;

but its cargo.toml does NOT include the compiler_builtins dependency. Instead my main crate has in the cargo.toml:

[dependencies.compiler_builtins]
features = ["mem"]
git = "https://github.com/rust-lang-nursery/compiler-builtins"

[dependencies.dummy]
version = "0.1.0"
path = "../dummy"

But I still get:

4 | extern crate compiler_builtins;
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't find crate
The docs say " To do that, add this crate somewhere in the dependency graph of the crate you are building:"
Which to me implies that you don't need the compiler_builtins dependency in dummy, as long as it's somewhere in the graph (i.e. in the caller library)
David McGillicuddy
@djmcgill
May 15 2017 12:24
If I do move the compiler_builtins dependency into the dummy crate then it works just fine. Does it have to be a downstream dependency then? If so then https://github.com/japaric/cortex-m-rt needs to be batched because it does not have compilter_builtins in its toml or and downstream ones - instead its docs say to put it in the caller upstream dependency like I'm trying.
Denis Lisov
@tanriol
May 15 2017 12:36
@djmcgill What happens if you have the compiler_builtins dependency on the main crate and omit the extern crate compiler_builtins; from dummy? Can you still use them from dummy?
David McGillicuddy
@djmcgill
May 15 2017 12:58

That's a good question, how would I actually test that? I tried

#![no_std]
use core::intrinsics::transmute;

pub fn mod_xy(x: i32) -> u32 {
    unsafe { transmute(x) }
}

in dummy/lib.rs, and called that function from my main library but it works (compiles into a binary) even if I don't include #![feature(compiler_builtins_lib)] in dummy at all...

Denis Lisov
@tanriol
May 15 2017 13:03
Exactly. In my understanding, the compiler_builtins_lib feature is not required to compile any (non-root) library crate. It is only the final link step that will require it to be used somewhere.
David McGillicuddy
@djmcgill
May 15 2017 15:09
In any case @tanriol cortex-m-rt has extern crate compiler_builtins; and no dependency in the toml so the example there isn't working. I'll raise an issue and have the discussion there. Thanks for your help.
Fra ns
@snarf95_twitter
May 15 2017 19:25
I'm having issues with following code:
struct PascalAlgorithm {
    previous_values: HashMap<(u32, u32), u32>,
}

impl PascalAlgorithm {
    pub fn new() -> Self {
        PascalAlgorithm { previous_values: HashMap::new() }
    }

    pub fn pascal(&mut self, row: u32, col: u32) -> u32 {
        self.previous_values
            .entry((row, col))
            .or_insert(if col == 0 || col == row {
                           1
                       } else {
                           self.pascal(row - 1, col - 1) + self.pascal(row - 1, col)
                       })
            .clone()
    }
}
error[E0499]: cannot borrow*selfas mutable more than once at a time
why is this not legal?
Denis Lisov
@tanriol
May 15 2017 19:31
First, this is not a good idea - your recursion is used in any case.
Ingvar Stepanyan
@RReverser
May 15 2017 19:31
because self is already borrowed as part of entry
Fra ns
@snarf95_twitter
May 15 2017 19:32
@tanriol what do you mean?
Ingvar Stepanyan
@RReverser
May 15 2017 19:32
@snarf95_twitter that you execute recursion anyway
it has to be in a or_insert_with closure and not just using or_insert with expression - otherwise it always executes
Denis Lisov
@tanriol
May 15 2017 19:33
You calculate the argument to or_insert before checking presence of (row,col) in the hashmap
Fra ns
@snarf95_twitter
May 15 2017 19:34
ohhh
Denis Lisov
@tanriol
May 15 2017 19:35
You could try using or_insert_with, but the closure will still be executed while the hashmap is borrowed, thus unable to do a recursive call.
Fra ns
@snarf95_twitter
May 15 2017 19:35
I see
Ingvar Stepanyan
@RReverser
May 15 2017 19:38
you could work around this by using RefCell, but in this particular case I think it's easier to just not use Entry API and instead normally 1) check if item exists, 2) recurse, 3) insert
(to be honest cases with partial borrowing are ones where it's always tempting to just retrieve pointer and go full unsafe :D )
Denis Lisov
@tanriol
May 15 2017 19:40
@RReverser Note that in this case you cannot do it.
Ingvar Stepanyan
@RReverser
May 15 2017 19:40
cannot do what?
Denis Lisov
@tanriol
May 15 2017 19:41
Go unsafe :-)
Ingvar Stepanyan
@RReverser
May 15 2017 19:41
You can always go unsafe! :D
Fra ns
@snarf95_twitter
May 15 2017 19:41
RefCell?
Denis Lisov
@tanriol
May 15 2017 19:43
With the corresponding consequences, sure :-) but a recursive tree, with each call reserving an entry in the HashMap... unsafety up to a segfault expected :-)
Ingvar Stepanyan
@RReverser
May 15 2017 19:44

/quote With the corresponding consequences, sure

that's entire point of unsafe :D

Fra ns
@snarf95_twitter
May 15 2017 19:50
I liek ma code fancy
Ingvar Stepanyan
@RReverser
May 15 2017 19:51
@tanriol just for the sake of example (== for fun :smile: ):
impl PascalAlgorithm {
    pub fn new() -> Self {
        PascalAlgorithm { previous_values: HashMap::new() }
    }

    pub fn pascal(&mut self, row: u32, col: u32) -> u32 {
        let value = match self.previous_values.entry((row, col)) {
            Entry::Occupied(entry) => return *entry.get(),
            Entry::Vacant(entry) => entry.insert(1) as *mut u32
        };

        unsafe {
            if col != 0 && col != row {
                *value = self.pascal(row - 1, col - 1) + self.pascal(row - 1, col);
            }

            *value
        }
    }
}
in this case we do know that nobody else is supposed to touch that item, so it will work ¯_(ツ)_/¯
not saying it's a good idea or something though
Ingvar Stepanyan
@RReverser
May 15 2017 20:00
@snarf95_twitter anyway, in your case this is probably the easiest solution (albeit not the most efficient, but it's probably not very important here):
pub fn pascal(&mut self, row: u32, col: u32) -> u32 {
    if col == 0 || col == row {
        return 1;
    }
    let key = (row, col);
    if let Some(&value) = self.previous_values.get(&key) {
        return value;
    }
    let value = self.pascal(row - 1, col - 1) + self.pascal(row - 1, col);
    self.previous_values.insert(key, value);
    value
}
Denis Lisov
@tanriol
May 15 2017 20:01
@RReverser And then your argument is big enough to force hashmap reallocation during recursion and BOOM!
Ingvar Stepanyan
@RReverser
May 15 2017 20:01
@tanriol heh, yeah, fair enough
I wouldn't use HashMap for this in the first place though :P
Fra ns
@snarf95_twitter
May 15 2017 20:02
what would you use?
Ingvar Stepanyan
@RReverser
May 15 2017 20:02
but very good point and example of why Rust borrowing rules are the way they're
Fra ns
@snarf95_twitter
May 15 2017 20:02
heh
@RReverser thanks for the help. Probably going to do this the 'safe' way even though the entry one is really cool although I don't really understand it.
Ingvar Stepanyan
@RReverser
May 15 2017 20:05
@snarf95_twitter entry one is really nice when you want to modify something in place after you already found the "entry" for it in the map (or didn't), but not when you need to do something with the same hashmap in between
otherwise due to the mentioned relocations this entry could be pointing to the wrong place, unless you box each item, which would make it awfully inefficient
also, would this be a real-world task, I'd suggest to make measurements before adding such caching - on relatively small inputs it might be easily a case that tail-recursive function will be faster than the one with cache due to extra overhead
Fra ns
@snarf95_twitter
May 15 2017 20:18
yeah this is mostly for quick exercises... I'm not trying to compete with this code or use it in RL. :smile: I guess I really should read the book about borrowing and stuff, I'm not quite sure I fully understand.
I get like a 'cool' idea for implementation and try it out...
Jonas Platte
@jplatte
May 15 2017 21:28
@snarf95_twitter Use the second edition of the book though. The ownership chapter there is a lot better than in the original one.