Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
    MCF
    @mcf-rocks
    where does cargo put it's code?
    tanriol
    @tanriol:matrix.org
    [m]
    @mcf-rocks: What do you want to do?
    MCF
    @mcf-rocks
    i want to know where cargo downloads the stuff it downloads
    $ cargo build
        Updating crates.io index
       Compiling libc v0.2.66
       Compiling rand v0.4.6
       Compiling rand v0.3.23
       Compiling hello_opensource v0.1.0 (/opensource/hello_opensource)
        Finished dev [unoptimized + debuginfo] target(s) in 4.48s
    where is the source code for rand?
    i want to look at it
    tanriol
    @tanriol:matrix.org
    [m]
    If you want to read it, you can find it somewhere in $HOME/.cargo/registry/src/
    RuRu92
    @RuRu92
    Anyone verse with mysql for rust?
    RuRu92
    @RuRu92

    Trying to build an abstraction for executing queries. Got into a little mess, maybe someone knows.

    Basically, I want to do something like this

     let fetch_users_query = |mut tx: Transaction|
                tx.query_map(
                    "SELECT id, role, name from user",
                    |(id, role, name)| {
                        Principal { id, role, name }
                    },
                );
    
            let users = db.in_transaction(AccessMode::ReadOnly, fetch_users_query);

    now this is all fine, in a sense

    But here is the issue

      return match action(tx) {
                Ok(res) => {
                    tx.commit();
                    return &res;
                }
                Err(x) => {
                    if db_access_mode != AccessMode::ReadOnly {
                        tx.rollback();
                    }
                    panic!(x);
                }

    Now if I do this, the tx is borrowed and not accessible in the tx.rollback

    The method that does this has the following signature

    pub fn run_in_transaction<R>(&self, db_access_mode: AccessMode, action: fn(con: Transaction) -> Result<R>) -> R

    I can have closer to take the reference, but I seem to end up in the weird reference entanglement. I cant seem to figure it out

    tanriol
    @tanriol:matrix.org
    [m]
    @RuRu92: Sounds like you need to have something like let result = action(tx); return match result { ... }... actually, that won't help.
    Your action is defined to consume transaction by value, and that will leave you without access to the transaction.
    RuRu92
    @RuRu92
    But then if I make action to take a transaction by reference. and change that action now works on mutable reference of transaction.
    I get the following error
      let users = db.in_transaction(AccessMode::ReadOnly, fetch_users_query);
       |                                                               ^^^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found mutable reference
    RuRu92
    @RuRu92
    Changing signature to something that expects a mutable reference as return?
    RuRu92
    @RuRu92

    Hmm.. now I managed to get this error

    = note: LINK : fatal error LNK1104: cannot open file

    RuRu92
    @RuRu92

    Got it working.. Would like some verification on if its done in correct way

     pub fn in_transaction<'a, R>(&self, db_access_mode: AccessMode, action: fn(con: &mut Transaction) -> Result<R>) -> R {
            let pool = self.pool.clone();
            let mut db_conn = pool.get_conn().expect("Unable to establish connection");
    
            let mut tx: Transaction = db_conn.start_transaction(TxOpts::default()
                .set_access_mode(Some(db_access_mode)))
                .expect("Failed to initialise transaction");
    
               return match action(&mut tx) {
                   Ok(res) => {
                       tx.commit().expect("Failed to commit");;
                       return res;
                   }
                   Err(x) => {
                       if db_access_mode != AccessMode::ReadOnly {
                           tx.rollback().expect("Failed to rollback");
                       }
                       panic!(x);
                   }
               };
            }

    and the caller

            let db = &data.db;
    
            let fetch_users_query = |tx: &mut Transaction|
                tx.query_map(
                    "SELECT id, role, name from user",
                    |(id, role, name)| {
                        Principal { id, role, name }
                    },
                );
    
            let users = db.in_transaction(AccessMode::ReadOnly,  fetch_users_query);
    Let me know what could be done better
    tanriol
    @tanriol:matrix.org
    [m]
    Looks good to me.
    RuRu92
    @RuRu92
    Nice, thanks @tanriol:matrix.org !
    MCF
    @mcf-rocks
    How to take action on not match
    pub enum Animal {
        Dog(u64),
        Cat,
    }
    
    fn main() {
        let a = Animal::Dog(3);
        if let Animal::Dog(n) = a {
            println!("dog {}",n);
        }
    }
    if it's anything other than Animal::Dog -- do something
    tanriol
    @tanriol:matrix.org
    [m]
    By adding an else ;-)
    MCF
    @mcf-rocks
    @tanriol:matrix.org without an empty if clause
    like in C
    if ( !something ) {
      printf("hello\n");
    }
    tanriol
    @tanriol:matrix.org
    [m]
    @mcf-rocks: Either an empty if, or a match with an empty branch for that case.
    Sorry, there's also if ! matches!(a, Animal::Dog(_)) { ... }
    MCF
    @mcf-rocks
    @tanriol:matrix.org so the only way to do it, without a tacky empty branch, is to place the word match between two exclamation marks - meaning totally different things... it's like god fell asleep and rust happened.
    thx for your help tho, is appreciated
    tanriol
    @tanriol:matrix.org
    [m]
    Well, you can also write or derive functions that would allow you to if !a.is_dog() { ... }, but there are none by default.
    RuRu92
    @RuRu92

    trying to understand closures/function pointers

    So in java it would be simple to have do this

    (db) -> { doSomething(someData, db); db.doMore(other, db) };

    now in rust I have trouble with scoping other variables

     return |tx: &mut Transaction| {
                let user_storage = UserStorage {};
                user_storage.create_from(user_data, tx)
            };

    Does user_data needs to be passed as a param to closure? Can it be done otherwise? Not having to pass it as param ?
    I am getting this error

       | |_________^ expected fn pointer, found closure
       |
       = note: expected fn pointer `for<'r, 's> fn(&'r mut Transaction<'s>) -> std::result::Result<std::string::String, mysql::Error>`
                     found closure `[closure@src\service\mod.rs:42:16: 46:10]`
    tanriol
    @tanriol:matrix.org
    [m]
    @RuRu92: There's a difference between function pointers (fn(args) -> output, cannot capture variables) and closures (impl Fn / FnMut / FnOnce(args) -> output, can capture variables). A closure that does not capture anything can be converted to a function pointer, and that's probably why you haven't noticed this problem before.
    RuRu92
    @RuRu92
    Ah, so I was working with function pointer, as my closure was not capturing anything
    So how should i change my signature and implement closure to be Fn/FnMut ?
    tanriol
    @tanriol:matrix.org
    [m]
    What's your signature?
    Ah, I see it above. I think that changing action to action: impl FnOnce(con: &mut Transaction) -> Result<R> should work if you don't need object safety.
    @RuRu92: By the way, an off-topic question: do I understand correctly that Java closures do not support checked exceptions like SQLException? Learning some Java now, and after Rust it feels... strange.
    RuRu92
    @RuRu92

    @tanriol:matrix.org
    Thanks, I will try that out! Why would it not give me object safety? Curious to understand how to make good rust code.

    As for the Java.
    If its in the lambda, you have to explicitly handle checked exceptions using try-catch, and convert that to a runtime exception.
    It may seem strange, but its other way around for me. Done Java for so many years, other languages seem so foreign :D
    But I am enjoying Rust, want to master it!

    RuRu92
    @RuRu92

    @tanriol:matrix.org
    To make it looks nicer when handling exception throwing code, you can implement a throwing functional interface.

    something like

    @FunctionalInterface
    public interface ThrowingConsumer<T, E extends Exception> {
        void accept(T t) throws E;
    }

    And then you when you call that, it will look better

    tanriol
    @tanriol:matrix.org
    [m]
    Object safety does not allow type (or const) generics because Rust does not do automatic type erasure. There are ways around that, usually by splitting the trait into two - the object-safe "core" and the "extras" for better ergonomics.
    RuRu92
    @RuRu92
    So for my case. the unsafe part is that I have generic in the Result<R> ?
    How would handle this?
    tanriol
    @tanriol:matrix.org
    [m]
    First, if you don't need in_transaction to be a part of an object-safe trait, you don't need to do anything :-)
    RuRu92
    @RuRu92

    So you saying that this is fine way to do it?
    I assume this code isnt going to be problematic due to object unsafety?

    Want to have this as production viable code :)

    tanriol
    @tanriol:matrix.org
    [m]
    This is a fine way - it has some limitations, but these may not matter for your use case.
    RuRu92
    @RuRu92
    Perfect! I can then continue on expanding the code.
    Once I got something full fledged, you could take a look at the repo?
    I like feedback :D
    tanriol
    @tanriol:matrix.org
    [m]
    If I have enough time.
    MCF
    @mcf-rocks
    how to use generic constants?
    fn from_str<const N: usize>(s: &str, N: usize) -> Box<[u8; N]> {
        return Box::new([1;N]);
    }
    how?
    tanriol
    @tanriol:matrix.org
    [m]
    You don't need N: usize in function arguments.