These are chat archives for rust-lang/rust

13th
Sep 2018
Anirudh Vyas
@AnirudhVyas
Sep 13 2018 02:05
hello there - does anyone know if there's a native rust client available for HDFS?
hi @Ichoran glad to see you here ... did not know that you are into Rust, thought you were scala person. Beginning to take a stab at introductory stuff myself, hope to ask more questions and learn...
John
@gitlabaccount624_gitlab
Sep 13 2018 04:38

hi, can someone help me fix this borrow checker error? not sure what's wrong:

error[E0507]: cannot move out of captured outer variable in an `Fn` closure
   --> src\main.rs:397:17
    |
391 |     let pool = Pool::new(manager).expect("Error creating Postgres connection pool!");
    |         ---- captured outer variable
...
397 |             db: pool
    |                 ^^^^ cannot move out of captured outer variable in an `Fn` closure

code:

struct State {
    db: Pool<ConnectionManager<PgConnection>>
}

let manager = ConnectionManager::<PgConnection>::new("querystring");
let pool = Pool::new(manager).expect("Error creating Postgres connection pool!");

server::new(move || App::with_state(State {
    db: pool
})
i'm trying to move pool into that state struct for the server but rust doesn't like that for some reason
Timothy Shoaf
@timshoaf
Sep 13 2018 04:39
Do you need to declare pool above the closure and have it capture? or can you happily instantiate it inline there inside the body of the closure with db: Pool::new(manager...
John
@gitlabaccount624_gitlab
Sep 13 2018 04:40
i'll try that
ok it didn't work because it gave me that line for manager but then i inlined the manager line in the same call and then it worked

sooo uhh two questions

1) this line is really long is there not a better way?
2) why did that work?

Timothy Shoaf
@timshoaf
Sep 13 2018 04:41
Correct me if I'm wrong (I'm a bit of a novice), but the ownership you have first transfers via the move semantics into the body of the closure, then attempts to again move it into the State struct passed into the associated function.
You could explicitly define the body of the closure like
John
@gitlabaccount624_gitlab
Sep 13 2018 04:42
oh u cant move twice i guess?
Timothy Shoaf
@timshoaf
Sep 13 2018 04:43
server::new(move || {
    let manager = ConnectionManager::<PgConnection>::new("querystring");
    let pool = Pool::new(manager).expect("Error creating Postgres connection pool!");
    App::with_state(State {
        db: pool
    }
}
John
@gitlabaccount624_gitlab
Sep 13 2018 04:43
hmm ok i try that
nice that worked too
so u can't move something twice or something?
Timothy Shoaf
@timshoaf
Sep 13 2018 04:46
I am not entirely sure what is preventing the ownership transfer from the closure itself into the thing returned by the Application instance returned by the closure.
John
@gitlabaccount624_gitlab
Sep 13 2018 04:47
okie dokie well this works anyway so thanks!
Timothy Shoaf
@timshoaf
Sep 13 2018 04:47
The number of times shouldn't matter, so it likely has something to do with the way ownership works in closures; I am sorry I can't be of more help, my experience is somewhat limited and it has been some time.
John
@gitlabaccount624_gitlab
Sep 13 2018 04:48
it's all good it's compiling so i'm happy
Timothy Shoaf
@timshoaf
Sep 13 2018 04:50
<3
Sam Johnson
@sam0x17
Sep 13 2018 05:31
how can I make something like this work?
        let mut total = 0;
        let mut limits_reached = 0;
        let mut st = Stream::new();
        st.on_data(|data| {
            total += data.len();
        });
        st.on_limit(2, || {
            limits_reached += 1;
        });
        let dat = [0u8, 1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8, 9u8, 10u8];
        st.write(&dat[0..dat.len()]);
        assert_eq!(limits_reached, 5);
        assert_eq!(total, 10);
error[E0502]: cannot borrow `limits_reached` as immutable because it is also borrowed as mutable
  --> src/tests.rs:18:20
   |
13 |         st.on_limit(2, || {
   |                        -- mutable borrow occurs here
14 |             limits_reached += 1;
   |             -------------- previous borrow occurs due to use of `limits_reached` in closure
...
18 |         assert_eq!(limits_reached, 5);
   |                    ^^^^^^^^^^^^^^ immutable borrow occurs here
19 |         assert_eq!(total, 10);
20 |     }
   |     - mutable borrow ends here

error[E0502]: cannot borrow `total` as immutable because it is also borrowed as mutable
  --> src/tests.rs:19:20
   |
10 |         st.on_data(|data| {
   |                    ------ mutable borrow occurs here
11 |             total += data.len();
   |             ----- previous borrow occurs due to use of `total` in closure
...
19 |         assert_eq!(total, 10);
   |                    ^^^^^ immutable borrow occurs here
20 |     }
   |     - mutable borrow ends here

error: aborting due to 2 previous errors
in other words, how can I set those variables from within those two closures, and then refer to the variables later in the code?
Timothy Shoaf
@timshoaf
Sep 13 2018 05:37
you are inherently trying to do something that is not threadsafe. Rust has no method of determining whether or not that closure is being executed synchronously or asynchronously and thus it won't let you run into this data race condition. You should be wrapping these in RefCells or something equivalent to handle the borrowing enforcement at runtime rather than compile time.
This chapter... which... imho is a little indirect... largely covers this problem: https://doc.rust-lang.org/book/2018-edition/ch15-05-interior-mutability.html
Guillaume P.
@TeXitoi
Sep 13 2018 09:04
what's this stream?
I think you can put from let mut st = Stream::new(); to st.write(&dat[0..dat.len()]); in a block, and it should work, but without the prototypes of on_data and on_limit, I'm not shure
@sam0x17
Madder
@Madder
Sep 13 2018 09:54
I'm quite new to Rust (apologies if this is not the right place for the question) and i'm wondering what's the state of debugging tools for Rust code. Are there any visual debug tools/IDEs available, and what are the best practices I should know when debugging Rust code. Most importantly for me, what are the most popular debug tools the community uses as things stand (either command line based or visual ones..)?
Vitaly
@Virtuos86
Sep 13 2018 10:12
@sam0x17 is this code works?
let mut total = 0;
let mut limits_reached = 0;
let mut st = Stream::new();
{
    st.on_data(|data| { total += data.len(); });
    st.on_limit(2, || { limits_reached += 1; });
}
let dat = [0_u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
st.write(&dat[0..dat.len()]);
assert_eq!(limits_reached, 5);
assert_eq!(total, 10);
trsh
@trsh
Sep 13 2018 10:33
    |
237 |                     draft: 1 as &i16
    |                            ^^^^^^^^^
    |
    = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
Whats the problem?
nm
Vitaly
@Virtuos86
Sep 13 2018 10:37
@trsh i16 is a primitive type, &i16 is not a primitive type
use draft: &(1 as i16)
trsh
@trsh
Sep 13 2018 10:39
@Virtuos86 yeah, tnx
Sylwester Rąpała
@xoac
Sep 13 2018 11:47
How can I convert BTreeMap<String, T> into serde_json::Value ?
of course T implements Into<serde_json::Value>
Lyle Mantooth
@IslandUsurper
Sep 13 2018 12:28
@trsh, why are you taking a reference to something that is Copy? Especially since the reference is bigger than your value?
Denis Lisov
@tanriol
Sep 13 2018 12:52
@IslandUsurper Pretty sure @trsh is working on his custom procedural macro, so this code is generated, not written.
Lyle Mantooth
@IslandUsurper
Sep 13 2018 12:52
Ah, that's a good reason.
trsh
@trsh
Sep 13 2018 13:10
:) It's fine
tnx guys
Pablo Martin Gore
@pablogore
Sep 13 2018 13:57
Hi , I'm pretty new working on rust , and I'm looking for the best way to implement microservices in Rust , someone could share some recommendation , how to communicate between each microservices , circuit breakers etc.
Ash
@ashthespy
Sep 13 2018 15:24
What is the 'best practice' way to collect struct elements from a Vev of such strucs?
#![allow(unused)]

#[derive(Debug)]
struct Somestruct {
    id: u32,
    name: String,
}

impl Somestruct {
    fn new(id:u32, name:String) -> Somestruct {
        Somestruct {
            id: id,
            name: name,
        }
    }
}

fn main() {
    let ids = [1,2,3];
    let names = ["a","b","c"];
    let mut vec_struct = Vec::new();

    // Init
    for i in 0..ids.len(){
        vec_struct.push(Somestruct::new(ids[i],String::from(names[i])));
        println!("{:?}", vec_struct[i]);    
    }

    // Extract ids again
    let my_ids = vec_struct.iter().map(|ss| ss.id).collect::<Vec<_>>();
    println!("{:?}",my_ids);

}
Zakarum
@omni-viral
Sep 13 2018 15:26
@ashthespy Use Iterator::collect it is the most common approach
First for loop could be replaced with iterator also
Ash
@ashthespy
Sep 13 2018 15:31
But I still have to use map to get the elements correct?
Zakarum
@omni-viral
Sep 13 2018 15:34
Yeap
Ash
@ashthespy
Sep 13 2018 15:42
Hmm, so this would be the right way?:
    let my_names = vec_struct.iter().map(|ss| ss.name.clone()).collect::<Vec<String>>();
Zakarum
@omni-viral
Sep 13 2018 15:43
Yeap
Ash
@ashthespy
Sep 13 2018 15:44
Is it possible to do this by reference as well?
PS: thanks for all the hand holding
Zakarum
@omni-viral
Sep 13 2018 15:44
What do you mean by "by reference"?
You can collect references if you like
Ash
@ashthespy
Sep 13 2018 15:45
Vec<&str> instead of Vec<String>
Lyle Mantooth
@IslandUsurper
Sep 13 2018 16:11
@ashthespy, that'd probably be .map(|ss| &ss.id), etc.
Ash
@ashthespy
Sep 13 2018 16:23
yep, got it :-) thanks!
Ichoran
@Ichoran
Sep 13 2018 17:30
@AnirudhVyas - I use whatever language makes it easiest to solve the programming problems I have (taking learning the language into account). I have a variety of problems for which Scala's performance is inadequate in some regard.
tsoernes
@tsoernes
Sep 13 2018 17:39
Given an ndarray of bools, is this likely the fastest way to find the number of elements that are true?
arr.fold(0, |n_used, &inuse| n_used + inuse as usize)
Ichoran
@Ichoran
Sep 13 2018 19:41
Is there a standard way to name a function that builds a new struct with some fields updated from the old struct?
I can always MyStruct { to_change: new_value, .. old_struct }, but sometimes I want a bit more functionality than that, so I'd like to have it as part of the impl of MyStruct.
Otto Chrons
@ochrons
Sep 13 2018 19:42
@Ichoran what do you use for communicating data structures between Scala and Rust? Protobuf, flatbuffers, JSON?
Ichoran
@Ichoran
Sep 13 2018 19:43
@ochrons - JSON so far. Haven't needed to communicate anything big.
Otto Chrons
@ochrons
Sep 13 2018 19:44
ok, we have a client written in Rust (on an e-bike) that talks to a Scala server, but as we move quite a lot of sensors logs, might need to go binary
(to be accurate, we don't have anything written yet, working on specs and requirements :smile: )
Ichoran
@Ichoran
Sep 13 2018 19:45
serde is incredibly fast. So is json_iter on the Scala side. I'm not sure how much "quite a lot" is, but the downside of JSON for me is mostly that it's lossy, not that it's slow.
(I am using my own jsonal, not json_iter, but same reasoning applies.)
Otto Chrons
@ochrons
Sep 13 2018 19:45
for us the speed is not important, data size is :)
Ichoran
@Ichoran
Sep 13 2018 19:45
Ah. Well, there's always compression.
I find zip + JSON easier to get right than protobuf or somesuch.
At least on the Scala side.
Otto Chrons
@ochrons
Sep 13 2018 19:46
right, makes sense
and for sensor data, using delta coding makes compression much more efficient
Timothy Shoaf
@timshoaf
Sep 13 2018 19:47
@Ichoran I personally come from a Java / C++ background so builder patterns and method chaining are what I typically when I want copy constructors with optional levels of detail… I don’t know that there is a ’standard’ design pattern for that anywhere, since, (considering a struct as a set of its fields) there are 2^n ways to include a subset of the fields in a copy constructor… so I don’t know that most people bother giving that a name. I think if you have some specific cases, then defining a well-named function that represents the semantics of that partial copy make sense — for example if you have a struct that has a few different types of identity operators defined modulo some number of its fields…
Lyle Mantooth
@IslandUsurper
Sep 13 2018 19:47
@Ichoran extend() perhaps. I know something in std uses that name for that kind of thing.
Ichoran
@Ichoran
Sep 13 2018 19:48
@IslandUsurper - That is really nonintuitive naming. It's not extended. It's the same thing! Just a field or two is different.
Lyle Mantooth
@IslandUsurper
Sep 13 2018 19:48
Well, it's more for collections than structs. /shrug
Ichoran
@Ichoran
Sep 13 2018 19:49
@timshoaf - I am basically after the name of the method for method chaining when it acts immutably rather than mutably.
If it's just for a single field that's enough to get started. set_myfield isn't right because that implies that it's setting it mutably.
Timothy Shoaf
@timshoaf
Sep 13 2018 19:50
If I were you I would define what it ‘means’ to take structA and produce a copy structB that is structA less a few fields different.
I guess if I had to pick a single word conjuct I might do
structA.with_field_name(new_value).with_other_field_name(other_new_value)
Ichoran
@Ichoran
Sep 13 2018 19:52
Yeah, I was thinking with or let. But I wasn't sure if there's already an established convention.
Timothy Shoaf
@timshoaf
Sep 13 2018 19:54
though this seems silly since that is basically built in. Where it isn’t as silly is if you roll up in the following manner: you give reasonable names to the field collections that matter to you. so I may have a struct User{} with instance user and a method .with_anonymized_information() that does the appropriate copy construct with things missing you want. or perhaps a user.with_new_address(number, street, city.. blah)
allowing you to immutably chain from one into the next
I don’t know that there is a particular name for that outside of just ‘method chaining’
Ichoran
@Ichoran
Sep 13 2018 19:55
In my case I want to hide things like a field actually being an option.
So I don't just want to use the built-in.
Timothy Shoaf
@timshoaf
Sep 13 2018 19:55
Are you entirely sure you don’t want to be returning a different type that adheres to a shared interface?
brb
Ichoran
@Ichoran
Sep 13 2018 19:56
Yes, I'm sure. In this case, having some optional data fields is the right solution, not 2^n types that have every possible combination of data fields.
But in the cases where there is an uninteresting zero, it makes more sense to have an API where the boring zero turns into a None instead of having Some(zero).
Ichoran
@Ichoran
Sep 13 2018 20:14
@timshoaf - Thanks for the ideas; I'm going with with_fieldname for now, in the case where the argument isn't exactly the field (e.g. the field is a String but the arg is Into<String>, the field is boxed but the arg isn't, and so on).
Sam Johnson
@sam0x17
Sep 13 2018 20:25
@Virtuos86 that still has the same immutable borrow issues when I compile .. here is the stream struct:
pub struct Stream<'a> {
    data_callback: Option<Box<dyn FnMut(&[u8]) + 'a>>,
    limit_callback: Option<Box<dyn FnMut() + 'a>>,
    pub remaining_bytes: usize,
    pub total_bytes: usize
}

impl <'a>Stream<'a> {
    fn get_data_callback(&mut self) -> &mut Box<dyn FnMut(&[u8]) + 'a> {
        if let Some(data_callback) = &mut self.data_callback {
            return data_callback;
        } else{
            panic!("attempted to write to a stream that doesn't have a data handler!");
        }
    }

    fn get_limit_callback(&mut self) -> &mut Box<dyn FnMut() + 'a> {
        if let Some(limit_callback) = &mut self.limit_callback {
            return limit_callback;
        } else{
            panic!("bad state");
        }
    }

    pub fn on_data(&mut self, callback: impl FnMut(&[u8]) + 'a) {
        self.data_callback = Some(Box::new(callback));
    }

    pub fn on_limit(&mut self, limit: usize, callback: impl FnMut() + 'a) {
        self.limit_callback = Some(Box::new(callback));
        self.remaining_bytes = limit;
    }

    pub fn write(&mut self, data: &[u8]) {
        if self.limit_callback.is_some() && data.len() > self.remaining_bytes {
            // amount to be written exceeds the current limit
            let remaining = self.remaining_bytes;
            self.remaining_bytes = 0;
            self.total_bytes += remaining;
            self.get_data_callback()(&data[0..remaining]);
            self.get_limit_callback()();
            self.write(&data[remaining..]);
        } else {
            // there is no limit or amount to be written does not exceed limit
            self.total_bytes += data.len();
            self.get_data_callback()(&data);
        }
    }

    pub fn connect(&mut self, target: &'a mut Stream<'a>) {
        self.on_data(move |data| { target.write(data) });
    }

    pub fn new() -> Stream<'a> {
        Stream {
            data_callback: None,
            limit_callback: None,
            remaining_bytes: 0,
            total_bytes: 0
        }
    }
}
Ichoran
@Ichoran
Sep 13 2018 21:05
Is there a way to apply a closure of some sort to a single element of a fixed-length array in order to generate a new copy of the array?
It works okay if I just want to assign the element:
fn update<A>(old: [A; 2], a: A) -> [A; 2] {
  let mut upd = old;
  upd[0] = a;
  upd
}
But I want to have something like upd[0] = f(upd[0]) instead.
Without A having to be Copy or something. I still want move semantics.
Elliot Stern
@PipocaQuemada
Sep 13 2018 21:17

I'm fairly new to Rust, so I'm currently working on writing a simple interpreter. I'm currently parsing by hand, and I'm having trouble understanding how to fix my current compilation error.

fn parse(code: &mut Chars, isLoop: bool) -> Option<Vec<AST>> {
    let mut acc = Vec::new();
    for c in code  {
        match c {
            '+' => acc.push(AST::Incr), 
            '-' => acc.push(AST::Decr),
            '>' => acc.push(AST::Left), 
            '<' => acc.push(AST::Right),
            ',' => acc.push(AST::Read),
            '.' => acc.push(AST::Write),
            '[' => match parse(code, true) {
                    Some(l) => acc.push(AST::Loop(l)),
                    None => return None
                   }
            ']' => if isLoop { return(Some(acc)) } else { return None },
            _ => return None
        }
    }
    if isLoop {
        None // unterminated loops are invalid
    } else {
        Some(acc)
    }
}

The error is use of moved value: *code; it's happening because I'm recursively passing the iterator inside the loop to parse whatever's between [ and ], and I want that recursive call to advance the iterator until just after the matching ]. What should I do to fix the code? Does it need to be fundamentally rewritten, or is there a way to fix it without too much trouble?

Ichoran
@Ichoran
Sep 13 2018 21:17
Can you use ``` on lines by themselves above and below your code so we get code formatting? Thanks!
Elliot Stern
@PipocaQuemada
Sep 13 2018 21:19
Sorry about that - I had accidentally not put a newline between the ``` and the start of the code, so I just needed to add that in. Bit weird that it requires that newline there, though.
Ichoran
@Ichoran
Sep 13 2018 21:20
If you mean ```fn foo() -> i32 { 7 } not working, that's because stuff on the same line is used to indicate explicitly which language it should syntax highlight for.
I'm not sure what Chars is, but I think the compiler is correctly complaining that you can't do that safely.
Ichoran
@Ichoran
Sep 13 2018 21:24
Ah, right, I'd forgotten about that.
Let me check if the problem is what I think it is. My intuition is still not very refined on these things.
Ichoran
@Ichoran
Sep 13 2018 21:31

Yeah, the for loop is just too greedy about such things. If you switch to iterating manually, it's okay. For instance, use

while Some(c) = code.next() {

instead of the for line.

Ichoran
@Ichoran
Sep 13 2018 21:42
Ugh, why is there any difference between struct Two<A> { one: A, two: A } and type Two<A> = [A; 2]; in terms of what is okay with lifetimes?
Ichoran
@Ichoran
Sep 13 2018 21:48
Bother, have to wait for NLL to fix it :(
Ichoran
@Ichoran
Sep 13 2018 22:25
What's the standard way to implement a pipe operator for Rust?
Ichoran
@Ichoran
Sep 13 2018 22:35
I guess this would be it for tap?
trait Taps<A> {
    fn tap(&mut self, mut f: impl FnMut(&mut A)) -> &mut A;
}

impl<A> Taps<A> for A {
     fn tap(&mut self, mut f: impl FnMut(&mut A)) -> &mut A {
        f(self); self
    }
}
(Easier with tap because you can assume it's side-effecting and therefore only really need to consider the mut case.)
Maybe just f: impl Fn(&mut A)?