Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Dijkstracula
Mar 18, 2003

You can't spell 'vector field' without me, Professor!

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 :v:

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'.

Adbot
ADBOT LOVES YOU

Dijkstracula
Mar 18, 2003

You can't spell 'vector field' without me, Professor!

Subjunctive posted:

Jon did his book, Rust for Rustaceans. It is probably what you want.
oh what the heck, how was I unable to find that it was actually published!

Thanks pal, this is getting put at the front of the queue

Dijkstracula
Mar 18, 2003

You can't spell 'vector field' without me, Professor!

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...)
This also stood out to me, I'm undercaffeinated and was up too late last night but seems like you don't want a sequencing point between the load and store which is what a CAS gives you

e:

Rust code:
thread::sleep(Duration::default());
curious about this line - not saying it's wrong but this is for my own edification: impl Default for Duration is 0 nanoseconds, but thread::sleep(nanoseconds(0)) is supposedly a no-op. What happens here in terms of the lock free behaviour here; is the point just to create a barrier for the compiler or does this actually do more than that (like the spin part of a userspace spinlock)?

Dijkstracula fucked around with this message at 16:21 on Sep 4, 2023

Dijkstracula
Mar 18, 2003

You can't spell 'vector field' without me, Professor!

Jo posted:

:stare: 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.

Dijkstracula
Mar 18, 2003

You can't spell 'vector field' without me, Professor!

Reading about the From and Into traits is where I would start.

Dijkstracula
Mar 18, 2003

You can't spell 'vector field' without me, Professor!

gonadic io posted:

While these are good they don't specifically answer the question.
Sure, I suggested From and Into because they’re the simplest example of “how does just assigning a thing to a seemingly-unrelated type turn it magically into that type” versus “how does serde do it in this particular case”, but I can see how that’d actually confuse the issue here :shobon:

Dijkstracula
Mar 18, 2003

You can't spell 'vector field' without me, Professor!

yeah I used to hang out in the discord a bunch but it seemed like mostly grouchy old-timers (which I don't necessarily fault them for, if I was answering basic questions over and over again I might turn that way too), but agreed that it isn't often optimal for learning

Dijkstracula
Mar 18, 2003

You can't spell 'vector field' without me, Professor!

Silly macro question that I can't find a good answer for:

I'm building a compiler for a research language in order to write some Rust in anger, and I have a unit test that looks like this, but unfortunately doesn't parse:

Rust code:
        let sort = ...
        ...
        assert!(matches!(
            sort,
            IvySort::Class(Class { 
                parent: None, 
                fields: [("x".into(), IvySort::Number), ("y".into(), IvySort::Number)].into()
                ..
            }))
        );
So, I'm forced to project out the enum discriminant and have a separate assert for the contents of the `fields` field without using matches!:

Rust code:

        let sort = match sort {
            IvySort::Class(cls) => cls,
            _ => panic!(),
        };

        assert!(matches!(
            sort,
            Class { 
                parent: None, 
                ..
            })
        );
        assert_eq!(
            sort.fields,
            [("x".into(), IvySort::Number), ("y".into(), IvySort::Number)].into()
        );
I don't particularly care about having to write it this way, but, is there a better way?

Dijkstracula
Mar 18, 2003

You can't spell 'vector field' without me, Professor!

Thanks!

gonadic io posted:

But it being inside the enum variant means you have to still have an explicit match in there
Sorry, do you mean that I can nested matches! calls? I'm fiddling with this but not pulling it off.

gonadic io posted:

Also you'll want to use the `fail` macro instead of just `panic` in your tests.
:nice: I did wonder if there was a more testy-way of doing this.

Dijkstracula
Mar 18, 2003

You can't spell 'vector field' without me, Professor!

Yeah I elided a bunch of extra fields to keep the example code tidy, but you're not wrong that I forgot about let-else

Dijkstracula
Mar 18, 2003

You can't spell 'vector field' without me, Professor!

I don’t really remember precisely what the Josephus problem is, but what limits you from using a VecDeque?

There’s also a linked list implementation in the standard library too.

Dijkstracula fucked around with this message at 18:55 on Dec 11, 2023

Dijkstracula
Mar 18, 2003

You can't spell 'vector field' without me, Professor!

I have a binary file format that I'd like to parse into a Rust structure and I'm wondering if serde is the wrong crate for it. A few issues that I've run into:

1) There's padding/unused bytes in the file format and serde doesn't seem to have a way of annotating something to the effect of "for this next field, fseek two bytes ahead", nor does it seem to be obvious that serde would treat a PhantomData<u16> as padding. (Besides, manually inserting padding fields into the struct just so serde does the right thing feels a bit funny anyway.)

2) There are lots of bitfields in the file format that I'd like to expand as enums with two discriminants. The problem seems to be that serde (reasonably) doesn't expose consuming data smaller than a byte, nor does it let me read all the bitfields in a byte and then produce multiple types.

Seems like the only way to do this is to just implement the entirety of Deserialize on my structure and doing everything manually. (edit: or just read in a blob of [u8] and std::mem::transmute stuff out as I see fit, which I'm not opposed to, per se, but...)

If that's the best way, then fine, but I suspect either serde is the wrong crate or I'm approaching this wrong?

Dijkstracula fucked around with this message at 20:00 on Dec 16, 2023

Adbot
ADBOT LOVES YOU

Dijkstracula
Mar 18, 2003

You can't spell 'vector field' without me, Professor!

tinaun posted:

Serde is not a parsing library.
Indeed, and I’m not in need of a parser here either. I reached to Serde first only because jonhoo made use of it in his BitTorrent client livestreams and it seemed like I was operating at a similar level of abstraction.

Thanks, all- sounds like nom is the thing I should use.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply