These are chat archives for rust-lang/rust

24th
Jul 2017
RuRu92
@RuRu92
Jul 24 2017 09:11
I am getting this error -> T cannot be shared between threads safely
How do I make my object safe for sharing between threads?
Having trouble understanding the Sync and Send on the rust docs
Max Frai
@max-frai
Jul 24 2017 09:27
@RuRu92 If you want to share T, it should be clonable. And sharing is just copying. If you want the same piece of data for all threads, you should use Arc (atomic reference counter) + Some Read/write lock (RWLock or Mutex, ...)
Sherab Giovannini
@Shaddy
Jul 24 2017 09:28

I'm doing another dummy codes, this one will read randomly some bits over a slice.


    use BitSize::{U8, U16, U32, U64};

    let bitsize = [U8, U16, U32, U64];

    while total_bits > 0 {
        let choice = rng.choose(&bitsize).unwrap();

        let bits = match *choice {
            U8 => rng.gen_range(0, 8),
            U16 => rng.gen_range(0, 16),
            U32 => rng.gen_range(0, 32),
            U64 => rng.gen_range(0, 64)
        };            

        let readen:u32 = match *choice {
            U8 =>  reader.read_u8(bits),
            U16 => reader.read_u16(bits),
            U32 => reader.read_u32(bits),
            U64 => reader.read_u64(bits),
        };

        if readen.is_ok() {
            total_bits -= bits as u32;
        } else {
            break;
        }
    }

The problem is that each read, returns a read_u8 => Result<u8, bitreader::BitStreamError> same for u16, etc.

Which is the best way to accomplish different return types? anyone has a tip :(?

thought that quote would not post the entire msg
Joonas Koivunen
@koivunej
Jul 24 2017 09:30
@Shaddy so you'd want your fn to return Result<u8, E> or Result<u16, E> or Result<u32, E> or Result<u64, E>?
Sherab Giovannini
@Shaddy
Jul 24 2017 09:32
its only a part of the entire function, it just loops until "total_bits" is consumed, the goal is to randomly read bits of reader until it fails.
to solve this particular problem, I did a .is_ok() for each match and then check for the bool after it
but the question was more related to that case, when you have multiple Result<u8, ...>, Result<u16, ...>, etc. for each match arm, if it is possible to "cast" results or you are forced to solve it inside the braces
this is the entire function:
fn simulate_bitreader(filename: &str) -> Result<(), Box<Error>> {
    let mut rng = rand::thread_rng();
    let mut test = File::open(filename)?;
    let mut bytes: Vec<u8> = Vec::new();
    let size = test.metadata()?.len() as usize;
    let number = test.read_to_end(&mut bytes)?;

    println!("filesize: 0x{:08X}", test.metadata()?.len());
    println!("vector-bytes that has been readen: 0x{:08X}", number);

    if number != size {
        return Err(Box::new(Error::new(ErrorKind::Other, format!("file has not {} bytes as expected", size).to_string())));
    }
    let mut reader = BitReader::new(&bytes);

    let mut total_bits:u32 = size as u32 * 8;

    println!("total_bits: 0x{:08X}", total_bits);
    let now = Instant::now();    

    use BitSize::{U8, U16, U32, U64};

    let bitsize = [U8, U16, U32];

    while total_bits > 0 {
        let choice = rng.choose(&bitsize).unwrap();

        let bits = match *choice {
            U8 => rng.gen_range(0, 8),
            U16 => rng.gen_range(0, 16),
            U32 => rng.gen_range(0, 32),
            U64 => rng.gen_range(0, 64)
        };            

        let read_error = match *choice {
            U8 =>  reader.read_u8(bits).is_err(),
            U16 => reader.read_u16(bits).is_err(),
            U32 => reader.read_u32(bits).is_err(),
            U64 => reader.read_u64(bits).is_err(),
        };

        if read_error { break; }        
        total_bits -= bits as u32;        
    }

    let elapsed = now.elapsed();    
    println!("bits readen in: {}.{} s", elapsed.as_secs(), elapsed.subsec_nanos());
    println!("bits left: {}", total_bits);
    Ok(()) 
}
Joonas Koivunen
@koivunej
Jul 24 2017 09:36
@Shaddy I'd create an enum like pub enum VarInt { U8(u8), U16(u16), ... } and write impl From<u8> for VarInt { ... } implementations for all the cases (or use a macro for that), then you could have a function fn read_something(...) -> Result<VarInt, E>
RuRu92
@RuRu92
Jul 24 2017 09:36
@max-frai I am aware of that and I have created an arc container which works fine for current thread. But when I pass it to another thread it blows up.
      accounts: Arc::new(Mutex::new(Vec::new()))
The issue is still there though
Sherab Giovannini
@Shaddy
Jul 24 2017 09:37
so @koivunej in that cases you should wrap type in order to handle multiple's
ill take a look over it, thanks
Joonas Koivunen
@koivunej
Jul 24 2017 09:39
@RuRu92 care to pastebin more of the code, how you implement the thread spawning and sharing and the error msg?
@Shaddy the From implementations are of course optional, but they allow for more idiomatic rust code... could be that the enum is not the most optimized for your case. I am not quite sure what you are trying to accomplish overall.
Sherab Giovannini
@Shaddy
Jul 24 2017 09:43
it is just a test over bitreader library
I'm creating a random 100MB file, and then simulating a random bitreading over it, just to test the performance
lemonxah
@lemonxah
Jul 24 2017 12:28
good day, having a hard time dereferencing a type inside of a Box,
fn mappend<A: HasAdd>(a1: &Box<A>, a2: &Box<A>) -> Box<A> {
    Box::new(**a1.add(&**other))
}
the error i get is type 'A' cannnot be dereferenced
Daan Rijks
@ijks
Jul 24 2017 12:32
What is the type of add?
lemonxah
@lemonxah
Jul 24 2017 12:33
pub trait HasAdd {
   fn add(&self, other: &Self) -> Self;
}
obviously this is just dummed down i dont actually have a trait called HasAdd :P
Daan Rijks
@ijks
Jul 24 2017 12:37
Hmm, play.rust-lang.org seems to be broken :s
Sandbox operation failed: Unable to execute the compiler: Out of memory (os error 12)

But I'm thinking: doesn't

Box::new(a1.add(*a2))

work?

RuRu92
@RuRu92
Jul 24 2017 12:39
@koivunej Sure can, here is the setup and how I am attempting to use threads
pub trait Account {
        fn print_details(&self);
        fn print_balance(&self);

        fn upgrade(&self);
        fn withdraw(&self, amount: u32) -> i32;
        fn deposit(&self, amount: u32) -> i32;
    }

    #[derive(Clone)]
    pub struct BasicAccount {
        id: String,
        balance: u64,
        max_balance: u64,
    }

    impl BasicAccount {
       pub fn new(balance: u64) -> BasicAccount {
            BasicAccount {
                id: Uuid::new_v4().simple().to_string(),
                balance: balance,
                max_balance: 100000,
            }
        }
    }

    impl Account for BasicAccount {

        fn print_balance(&self) {
            println!("AccountID: {} \nBalance: {}", self.id, self.balance)
        }

        fn upgrade(&self) {
            println!("Upgraded");
        }

        fn withdraw(&self, amount: u32) -> i32 {
            300i32
        }

        fn deposit(&self, amount: u32) -> i32 {
            unimplemented!()
        }

        fn print_details(&self) {
            unimplemented!()
        }
    }

 #[derive(Clone)]
    pub struct User {
        pub id: String,
        pub name: String,
        pub age: u64,
        pub gender: Gender,
        pub accounts: Arc<Mutex<Vec<Box<Account+Sync+Send>>>>
    }

    impl User {
        pub fn new(name: String, age: u64, gender: Gender) -> User {
            User {
                id: Uuid::new_v4().simple().to_string(),
                name: name,
                age: age,
                gender: gender,
                accounts: Arc::new(Mutex::new(Vec::new()))

            }
        }

        pub fn add_account<T: 'static + Account>(&mut self, account: T) {
            let acc = account;
            let mut accounts = self.accounts.lock().unwrap();
            accounts.push(Box::new(acc));
        }

        pub fn view_balance(&self) {
            let mut accounts = self.accounts.lock().unwrap();
            if accounts.len() == 1 {
                let account = &accounts.as_slice()[0];
                account.print_balance();
            }
        }
    }

fn main() {
    println!("-----------------------------");

    let mut me = User::new("RuRu".to_string(), 24u64, Gender::Male);
    println!("{}", me);

    let mut acc = BasicAccount::new(2000);

    let client_thread = thread::spawn(move || {
        me.add_account(acc);
        me.view_balance();
    });


    println!("id: {}", Uuid::new_v4().to_string());

}
lemonxah
@lemonxah
Jul 24 2017 12:39
yeah i wanted to do a play.rust-lang.org for you but it didn't work :)
@ijks no that doens't work
@RuRu92 why do you have age as u64? why not u8? i mean you cant be older than 254?
well i haven't heard of someone that old
RuRu92
@RuRu92
Jul 24 2017 12:47
That is certainly true! .. And would be more memory efficient, thanks for the tip
It's just something that I am used to in Java, any int is just an int in the end
lemonxah
@lemonxah
Jul 24 2017 12:48
but remember that u64 is huge memeory space allocated for something that is inherently small
so if you have an array of those users then there is wasted space :)
RuRu92
@RuRu92
Jul 24 2017 12:51
Valid point :)
But what about my modeling of Account and use of Arc for using vector of accounts for passing around threads?
Is that a bad approach and how can I get it work and what would be the better way to go about this? I am willing to learn :)
lemonxah
@lemonxah
Jul 24 2017 13:03
sorry i just started learning Rust not familiar with the threading patterns yet
Joonas Koivunen
@koivunej
Jul 24 2017 13:05
@RuRu92 the problem is that you are using Arc<Mutex<...>> inside your structures when you'd need to put your structs inside the Arc<Mutex<...>> containers, not only parts of those
@RuRu92 i can't immediatedly remember what is the kind of an error message you get at this point, but yeah if you could upload your sample to play.rust-lang.org it'd be easy to point out different ways of accomplishing this
@RuRu92 hmm let me take that back, looks like you are Sending both structs over to client_thread so I guess there's no problem related to what I just said. the error message is about the boxing and pushing that happens in add_account as your bounds in the Arc<Mutex<Vec<Account+Send+Sync>>> are different than what the add_account specifies for T (only 'static + Account, it should also have Send + Sync)
lemonxah
@lemonxah
Jul 24 2017 13:18

@ijks got it working with

Box::new((**self).mappend(&**other))

wrapping the **self in ( ) and i understand that it should work like that but i was hoping dereferencing it **self will then give me the methods on it

Daan Rijks
@ijks
Jul 24 2017 13:23
@lemonxah That's kind of odd though, Box<T> should implement Deref<T>, so you should be able to access methods on A without explicity dereferencing. Also, why are you dereferencing twice?
lemonxah
@lemonxah
Jul 24 2017 13:24
what do you mean derefferencing twice?
oh cause the input is &Box<A>
Daan Rijks
@ijks
Jul 24 2017 13:25
oh, i missed that
Then this should work too:
Box::new(a1.add(&**a2))
lemonxah
@lemonxah
Jul 24 2017 13:26
type mismatch
Wait, so now you're using mappend as a method, are you trying to implement a Monoid trait?
lemonxah
@lemonxah
Jul 24 2017 13:29
semigroup and monoid yes
i am trying to duplicate what i have now on play.rust-lang
give me a few seconds
lemonxah
@lemonxah
Jul 24 2017 13:34
ok ok so
i think this is what happens
self is the Semigroup
yes
its because self refers to the Box<A> which is the Semigroup and the Semigroup allready has the method mappend
so its because its not in a function like yours but rather in a impl for the Semigroup
Daan Rijks
@ijks
Jul 24 2017 13:40
Oh, I see. Because there's now an implementation of Semigroup for Box<A>, the one for A isn't used.
lemonxah
@lemonxah
Jul 24 2017 13:41
not just that but self as the first argument referes to the Semigroup "instance" for Box<A> so that doesn't auto deref it?
Daan Rijks
@ijks
Jul 24 2017 13:42
Yes.
So using (**self) and &**other is fine. But here's another way you could write it:
Box::new(self.as_ref().mappend(other.as_ref()))
lemonxah
@lemonxah
Jul 24 2017 13:43
ah ok are those the same thing?
which is better to use?
lemonxah
@lemonxah
Jul 24 2017 14:43
is there some way to reference an impl of a trait?
but generically
impl Monoid for i32 {
    fn mempty() -> Self { 0 }
}

impl<A: Monoid> Monoid for Box<A> [
    fn mempty() -> Self {
        Box::new( Monoid::<A>.mempty() )
    }
}
what i am looking for is a way to get the Monoid instance of the type A
Daan Rijks
@ijks
Jul 24 2017 14:47
<A as Monoid>::mempty() I believe.
lemonxah
@lemonxah
Jul 24 2017 14:47
so if i am using Box<i32> it should create a Box<i32>::new(0)
Daan Rijks
@ijks
Jul 24 2017 14:47
Or maybe A::mempty() is possible as well.
lemonxah
@lemonxah
Jul 24 2017 14:48
ah yes the second one works thank you
so much new syntax to learn
RuRu92
@RuRu92
Jul 24 2017 20:05

@koivunej Yeah adding Send + Sync solved one of the problems, not everything.

Lets say I want to get an account out of a vector by provided index. I get an error that about returned object not living long enough.

 pub fn get_account(&mut self, index: usize) -> &Box<Account+Sync+Send> {
            let mut accounts = self.accounts.lock().unwrap();
            &accounts.as_slice()[index]
        }
David Harvey-Macaulay
@alteous
Jul 24 2017 20:37
Does anybody know if the std::io::Read implementation of std::fs::File is blocking?
David Harvey-Macaulay
@alteous
Jul 24 2017 20:53
I ask because I want to use AsyncRead on regular files.