|
How simple? If there's no (and can never be) any fields in any of the variants, then that's a job for the ol' integer.
|
# ? Jul 3, 2023 15:54 |
|
|
# ? May 13, 2024 08:54 |
|
Otherwise, if you don't want to go via string parsing as above, a more complex approach could be an integer determinant and a great number of optional columns, but at least the unsafe code only exists in one well-defined place.
|
# ? Jul 3, 2023 15:55 |
|
gonadic io posted:How simple? If there's no (and can never be) any fields in any of the variants, then that's a job for the ol' integer. Exactly that simple. I haven’t used enum discriminants. How do I convert from an integer back to the enum? Google is telling me I need to write a try_from function. Is that correct?
|
# ? Jul 3, 2023 16:22 |
|
Databases have enum columns types as well.
|
# ? Jul 3, 2023 16:34 |
|
lifg posted:Exactly that simple. I've used I think this library before so I don't have to write out the cases myself: https://docs.rs/num-derive/latest/num_derive/derive.ToPrimitive.html
|
# ? Jul 3, 2023 18:03 |
|
I've been trying to write some Rust in my free time, and I guess I have to accept that I don't understand anything:code:
|
# ? Jul 4, 2023 15:37 |
|
The best place to start is with the compiler error message, and explain what you don't understand or why you think it shouldn't be complaining about that.
|
# ? Jul 4, 2023 16:50 |
|
I feel like that should probably work if you just used self.cache everywhere instead of giving it a name E: nope, I just tried and it doesn't, robostac is right gonadic io fucked around with this message at 16:58 on Jul 4, 2023 |
# ? Jul 4, 2023 16:50 |
|
The borrow checker isn't good enough to allow you to return references to the contents of a structure and modify a structure from the same function. On Current versions this needs to be implemented with Entry, but your code does work correctly with the next-generation borrow checker (polonius) that's available in nightly, but thats been in development for a while now and is still in progress.
|
# ? Jul 4, 2023 16:54 |
|
As far as I can tell you're running into the common issue where if let has a funky scope and even though you're returning from inside it, its borrow lasts until the outer scope ends. If that's the case one of the workarounds is to put the whole if let inside its own scope to force the borrow to be released. One of my least favourite rust constructs is the suggested workaround if your if let returns an owned/Copy item: code:
Yes that temporary binding is necessary. Threep fucked around with this message at 17:08 on Jul 4, 2023 |
# ? Jul 4, 2023 17:02 |
|
I've been playing around in the playground and I can't get either of those to work here.
|
# ? Jul 4, 2023 18:11 |
|
Here, this might be better for what you're trying to do:code:
|
# ? Jul 4, 2023 18:19 |
|
Fun Rust fact: it'll figure out initialization of a variable from a subsequent statement, even two branches of an `if`, so no dummy initializer is required (nor `mut`!!).Rust code:
Rust code:
Rust code:
|
# ? Jul 4, 2023 18:59 |
|
lifg posted:Exactly that simple. There's also this if you already use serde for (de)serializing stuff https://github.com/dtolnay/serde-repr
|
# ? Jul 5, 2023 09:44 |
|
Thanks everybody! I think I get it now, the first borrow is living longer than I expected due to a borrow checker limitation.
|
# ? Jul 5, 2023 15:25 |
|
Today I learned you can yeet in Rust: https://www.youtube.com/watch?v=BgCXrf_SG2E&t=110s
|
# ? Jul 7, 2023 18:08 |
|
I posted this in yospos but realized this might be a better place for it -- I've been building part of my PhD work in Rust in order to learn the language in anger, and I hit a milestone last night: 10,000 lines of code! In a Gladwellian sense, I'm now a Rust expert Except that of course I do not feel like a Rust expert in the way that, say, 10,000 lines of Java might make me legitimately proficient in that language. (here is a representative Rust file, as an example). For instance, I'm making heavy use of cloning to avoid the borrow checker yelling at me even though I'm _reasonably_ sure I could imagine using lifetimes (the project is a compiler and so most of the heavy lifting is tree-walking a program AST, so all the nodes in it will have the same lifetime). Also, there are plenty of data structures that require careful consideration in Rust that I could "just write" in a GCed language (or something where I explicitly control memory) - the above file contains, morally, a union-find data structure for a typechecking algorithm, but it got mutated into this weird "things get passed around as a `uint` which internally get looked up in a lookup table of actual values", which is insane to me but god if I could figure out how else to get it to work! Lots of little things, too - what's the right way to expose public things outside a module? Is it fine to just dump stuff in a mod.rs (kind of like a ML .mli file) or should that only be for use/pub mod directives? If I have a case where a function will either return an existing piece of data (which it could do by reference) in one code path and construct a new piece of data in another (which cannot be by reference), can I somehow do something smarter than cloning in the former case? The problem is that I'm working on it on my own and I don't have a good barometer for Good Rust Idioms, beyond "as a C programmer, do I imagine that doing it this way would bite me later on" or "as a functional programmer, can I express the thing that I'd just write in OCaml without having to worry about fn vs Fn vs FnOnce vs FunMut", and there's nobody around to yell at me in my pull requests. That whole Ira Glass quote about having enough taste to know that you don't have good taste, etc. I've thumbed through a few Rust books and the problem is that they tend to be geared towards either newbies to the language ("this is what an `if let` is, this is how pattern matching works, etc) or total newbies to programming, inexplicably ("this is a for loop"). What's a good intermediary Rust resource for learning good taste? I know Jon Gjengset was at some point working on a book that sounded like this but I guess he's fallen into the AWS employee black hole or somethin'.
|
# ? Jul 30, 2023 16:39 |
|
Jon did his book, Rust for Rustaceans. It is probably what you want. Also Aria’s linked-list book and maybe even her blog posts.
|
# ? Jul 30, 2023 16:51 |
|
Subjunctive posted:Jon did his book, Rust for Rustaceans. It is probably what you want. Thanks pal, this is getting put at the front of the queue
|
# ? Jul 30, 2023 16:53 |
|
I am late to the party, but I saw a lot of talk of stuff being "managers." That's always been a cringe sign for me that I don't know where my abstractions really are. I can't think of a better term but I know there's something in common, so it becomes a manager. I still suck at the traits stuff and how abstraction is done in Rust, so I don't have any better thing to say about that. Even if I did, the situations are all contextual and independent of each other. I just wanted to flag a potential code smell.
|
# ? Aug 1, 2023 10:51 |
|
Rocko Bonaparte posted:I am late to the party, but I saw a lot of talk of stuff being "managers." That's always been a cringe sign for me that I don't know where my abstractions really are. I can't think of a better term but I know there's something in common, so it becomes a manager. Agreed! Naming things is hard
|
# ? Aug 1, 2023 12:16 |
|
Writing hella code and figuring out what abstractions/features/patterns you like and don’t like yourself is just about the best way to learn IMO. With that kind of experience you can read stuff and actually say “oh I’ve run into that problem” and more accurately judge and contextualize any advice you get from a book.
|
# ? Aug 15, 2023 13:35 |
|
I am linting some of my first real code with Clippy and have some goofy stuff going on. Here's one paraphrased:code:
Edit: I guess it wasn't Clippy but some linting in CLion that decided to be goofy about it. Clippy actually hated cloning the value. Rocko Bonaparte fucked around with this message at 22:46 on Aug 16, 2023 |
# ? Aug 16, 2023 22:19 |
|
I am looking for stuff--preferably text--on how to use the abstractions in Rust (generics, traits, whatever) in particular to make code easier to unit test with mocks. I'd like to swap out system code for fake stuff so I can verify all the intermediate handling logic I have to write.
|
# ? Aug 26, 2023 21:50 |
I'm kicking myself a bit for rewriting a big chunk of this and working myself into a corner. I'm processing a stream of video data at ~120Hz. I have a preallocated ring buffer with space for N image captures. The buffers are also preallocated, so the camera thread is just going through, picking the next element in the ring buffer, and copying contents to that. Works pretty okay. Or it would, if I didn't have to hand out a reference to elements in the ring buffer. code:
I have four ideas for solutions but none of them seem very elegant: 1) Go back to the approach that used channels, but instead of just tx/rx have a tx/rx for sending images AND a tx/rx for 'returning' images which can get reused. Pretty elegant in theory and the lack of locking probably will be faster. Problem: having to return images after being done processing feels too much like manual memory management. 2) Pass a lambda into the read_next_frame_blocking. I rather like this, but I think using closures to do stuff could lead to more hardship in the future. 3) Have another fake image that I swap into the Vec in place of the actual image, then swap it back at return time. This feels risky and dumb. 4) Go back to the channel approach. Bummer to throw away the work and bummer to have the allocations, but it's maybe the nicest going forward. I'm sure there's a better approach to all of this but I think maybe I've got tunnel vision and I'm just not seeing the obvious. Will probably sleep on it and try again tomorrow night, but anyone sees it that would be appreciated. EDIT: I ended up with a variant of #1. I throw Arc<ImageData> into the pipe and use Arc::strong_count(i) to check if images are dropped elsewhere. It's not _as_ ergonomic as passing around just the refs, but I'm really happy with it. Jo fucked around with this message at 06:57 on Sep 4, 2023 |
|
# ? Sep 4, 2023 06:07 |
|
Jo posted:I have four ideas for solutions but none of them seem very elegant: I just want to note that you never actually stated what the problem was. I assume that code didn't borrow check or work because of the returned reference lifetime, because that's what it sounds like from these solutions. I agree (4) should be out, there *should* be a workable enough way to avoid the allocation here. I'm assuming the performance would be nice here. All of 1,2,3 seem like reasonable choices. I don't think 3 should be considered that terrible, considering it's something like what std::mem::replace/take do, so it's sort of a "pattern" in Rust. (2) is probably what I would have chosen. I'm curious why you think it'd be a problem in the future? This is the most like many other solutions to "I want a reference to it but you can't *return* a reference". The other maybe-but-haven't-thought-it-through possibility is something like MutexGuard. Return not the reference but something that's basically a reference but now has a lifetime parameter that's correctly constrained in the sense of "lives longer than the function call, but shorter than self's lifetime and shorter than next frame or whatever". (Also, bit sus for an atomic load/store. Even if purely single threaded I'd probably write a function to do that increment with a compare and swap, just to leave my mind at ease...) (Also also, I assume there are existing ring buffer-based channel implementations, are you sure you need a custom one?)
|
# ? Sep 4, 2023 16:06 |
|
A variation on #3 that you might like more would also be to have the elements of your ring buffer be an Option<image::RgbImage>, which makes the std::mem::take solution pretty straightforward (since taking ownership just replaces it with None)crazypenguin posted:(Also, bit sus for an atomic load/store. Even if purely single threaded I'd probably write a function to do that increment with a compare and swap, just to leave my mind at ease...) e: Rust code:
Dijkstracula fucked around with this message at 16:21 on Sep 4, 2023 |
# ? Sep 4, 2023 16:13 |
|
Speedwise, 3 but being very careful with uninit memory seems like it'd be the fastest. Why overwrite the previous images/uninit memory (on the first go around) until you need to? It's not like there's difficult control flow or only partial image writes or anything.
|
# ? Sep 4, 2023 16:27 |
|
Jo posted:I'm kicking myself a bit for rewriting a big chunk of this and working myself into a corner. It looks like you're trying to roll your own SPSC ring buffer. Implementing custom synchronization primitives requires unsafe (and extreme care). You could try using an off the shelf ring buffer like that of the `rtrb` crate instead.
|
# ? Sep 4, 2023 18:03 |
A huge thank-you to everyone who replied. I'll try to get to all of the remarks and go through them when I'm home from work. If anyone wants to look at the complete mess for their own curiosity: https://github.com/JosephCatrambone/MotionCaptureMk5/blob/main/src/camera_handler.rs crazypenguin posted:I just want to note that you never actually stated what the problem was. I assume that code didn't borrow check or work because of the returned reference lifetime, because that's what it sounds like from these solutions. D'oh. Yeah, lifetime was the issue, but even with a lifetime annotation I got a compiler error about moving data from inside the vec. crazypenguin posted:I agree (4) should be out, there *should* be a workable enough way to avoid the allocation here. I'm assuming the performance would be nice here. I guess my neurotic aversion to taking a closure as a parameter is just that -- neurosis rather than based on any real evidence. There's no harm in me making a method and giving it a try, so maybe I will when I get back home. crazypenguin posted:The other maybe-but-haven't-thought-it-through possibility is something like MutexGuard. Return not the reference but something that's basically a reference but now has a lifetime parameter that's correctly constrained in the sense of "lives longer than the function call, but shorter than self's lifetime and shorter than next frame or whatever". Dijkstracula posted:A variation on #3 that you might like more would also be to have the elements of your ring buffer be an Option<image::RgbImage>, which makes the std::mem::take solution pretty straightforward (since taking ownership just replaces it with None) It's sounding like there's support for the mem::swap. I'm still wrapping my head around how exactly I'd make that happen, but maybe I'm undercaffeinated. Dijkstracula posted:e: I did not realize this. It was a hold-over from years of Java programming -- sleep/yield(0) would relinquish thread control rather than actually sleeping. That's definitely not what I intended. I'll swap it for a delay by the frame time. Thank you for the correction -- that would have really hurt. Ralith posted:It looks like you're trying to roll your own SPSC ring buffer. Implementing custom synchronization primitives requires unsafe (and extreme care). You could try using an off the shelf ring buffer like that of the `rtrb` crate instead. I'd not heard of this, but it might save me a lot of trouble. Thank you! EDIT: One of the reasons I was almost-but-not-quite trying to roll my own ring buffer was this: the camera interface can capture to an _existing buffer_ and I was hoping to avoid allocating and pushing a new image for each frame. The existing ring buffer solutions will let a person push and pop, yes, but I didn't want to push and pop the data as much as I wanted to WRITE to the buffers and READ from them. So it was more of a... static buffer with spinning read/write heads? The difference being just whether there's an allocation/deallocation of an image. It's probably premature optimization but I've been bitten before by memory pressure when it comes to streaming video data. Jo fucked around with this message at 19:13 on Sep 4, 2023 |
|
# ? Sep 4, 2023 19:03 |
|
Jo posted:I did not realize this. It was a hold-over from years of Java programming -- sleep/yield(0) would relinquish thread control rather than actually sleeping. That's definitely not what I intended. I'll swap it for a delay by the frame time. Thank you for the correction -- that would have really hurt. Yeah, I figured you' were trying to just park the thread, Java-style - I should have also said that if you wanted to just relinquish control back to the scheduler, thread::yield_now() might be the thing you're after.
|
# ? Sep 4, 2023 19:56 |
Yup! That is indeed exactly what I was looking for. Thank you!
|
|
# ? Sep 4, 2023 20:56 |
Jo posted:I'd not heard of this, but it might save me a lot of trouble. Thank you! It looks like rtrb's Producer and Consumer implement Write and Read, respectively, so I think it might do what you want here? Worth at least trying IMO
|
|
# ? Sep 5, 2023 00:06 |
|
Jo posted:EDIT: One of the reasons I was almost-but-not-quite trying to roll my own ring buffer was this: the camera interface can capture to an _existing buffer_ and I was hoping to avoid allocating and pushing a new image for each frame. The existing ring buffer solutions will let a person push and pop, yes, but I didn't want to push and pop the data as much as I wanted to WRITE to the buffers and READ from them. So it was more of a... static buffer with spinning read/write heads? Yes, that's the idea behind ring buffers. Use a ring buffer of `u8` or whatever and write complete frames to it directly.
|
# ? Sep 5, 2023 05:48 |
|
Rust libs, especially specialist data structures like ring buffers, almost always will contort themselves to be pretty efficient and you can usually rely on them to not allocate when they don't have to
|
# ? Sep 5, 2023 06:53 |
Ralith posted:Yes, that's the idea behind ring buffers. Use a ring buffer of `u8` or whatever and write complete frames to it directly. I must be doing a crap job of explaining. For that I do apologize. The ring buffer in rtrb offers two methods that we care about, push() and pop(). I can push() a [u8] onto the ring buffer, but once the consumer pops the [u8] I can't reuse it, right? I would have to keep allocating new [u8]s, dumping the image data to them, and pushing them onto the ring buffer as the consumer pops them? What I had with the original setup: code:
code:
code:
|
|
# ? Sep 5, 2023 07:53 |
|
In the rtrb crate you want to have a ring buffer where the elements T is u8 NOT [u8] with capacity n*sizeof(image) and use read_chunk and write_chunk (possibly _uninit). They give you immutable and mutable references to the data respectively and you can overwrite the bytes without reallocating. It's slightly awkward to deal with generic byte slices instead of Image structs as your elements that you might expect but it absolutely does what you want it to.
|
# ? Sep 5, 2023 08:04 |
gonadic io posted:In the rtrb crate you want to have a ring buffer where the elements T is u8 NOT [u8] with capacity n*sizeof(image) and use read_chunk and write_chunk (possibly _uninit). They give you immutable and mutable references to the data respectively and you can overwrite the bytes without reallocating. It's slightly awkward to deal with generic byte slices instead of Image structs as your elements that you might expect but it absolutely does what you want it to. I glossed over those method. You're exactly right: read/write chunk looks perfect.
|
|
# ? Sep 5, 2023 17:07 |
|
hello. i decided to learn Rust this week and to get my hands dirty with it, I decided to build an authorization API that I previously built in Python. It's going well so far What I've got working is: a fully dockerized rust HTTP server (using Actix), Postgres, and Nginx I've got the app talking to the database and have written a few initial migrations to get the DB set up and have those run on app start a bunch of endpoints returning dummy data like POST /register, POST /login, GET /profile what I am struggling big time with is the actual rust code and was hoping someone could help me out. I know i should probably just take a pause and spend a couple days watching some more Youtube, but I'm really trying to learn by fire here. So basically what I'm trying to do is return multiple errors to the user, based on the request body they send to me. So this for example: JSON code:
JSON code:
Actix exposes the request JSON in either Bytes or actual JSON like so Rust code:
Rust code:
Rust code:
|
# ? Sep 26, 2023 18:14 |
|
|
# ? May 13, 2024 08:54 |
|
okay after some battling, here's what I came up with the endpoint: Rust code:
Rust code:
|
# ? Sep 26, 2023 20:42 |