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
The junk collector
Aug 10, 2005
Hey do you want that motherboard?
So I've decided to get back into programming after a very long time and Rust looked really interesting to learn but that also means I am a total neophyte.

What is the best way to declare a multi-dimensional array of structs? In this case, 2-D is all I'm working with but I might be on 3 or more before long. I need to be able to slice along any axis (but not an arbitrary made up diagonal axis) and I need to be able to decompose the array into a single vector. Row or column ordered, although as long as it can do one well, I'm not picky. Transpose of data along a specified set of 2 axis would also be swimming. To make this work well, it looks like everything needs to be adjacent in memory. I will need to be able to resize the array, but only very seldom. Size is not known at compile time because it is provided externally, although I can assume a default size state and resize at launch.

In this case, my struct is just a collection of bytes (type u8) organized for processing. I figured out that I can get them to stay together in memory and order by using repr(C).
I tried starting with Vec<Vec<T>> but that seems to be a list of pointers to vectors which makes total sense but doesn't work very well with my case. I've started using the ndarray library but it's giving me tons of trouble trying to initialize a new array if I want to use my struct. It seems like their should be a super simple way to do this, but I'm pulling my hair out. Does using a single vector ensure that data is contiguous even after a resize? If that's the case I could write my own struct around it to do indexing and slicing but it seems like this should be a common problem someone would have solved by now.

Adbot
ADBOT LOVES YOU

Anarchist Mae
Nov 5, 2009

by Reene
Lipstick Apathy
I've been refactoring rustdoc to improve readability, specifically for dyslexic people, could use some constructive criticism:

https://measlytwerp.github.io/rustdoc-reskin/std/

Search is still Todo.

necrotic
Aug 2, 2005
I owe my brother big time for this!
The content is pretty narrow, with a lot of space between the left nav and the content itself. I'd shift it left and widen it 10rem or so.

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

The junk collector posted:

Does using a single vector ensure that data is contiguous even after a resize?

Yeah.

The junk collector
Aug 10, 2005
Hey do you want that motherboard?

Awesome, thanks. I guess it's time to do a bunch of indexing.

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

The junk collector posted:

Awesome, thanks. I guess it's time to do a bunch of indexing.

You might find the Vec allocation chapters of the Rustonomicon interesting as well.

The junk collector
Aug 10, 2005
Hey do you want that motherboard?
I just wanted to say thank you. That is a very helpful read, and while I still don't understand everything, I am now well on my way to hating lifetimes instead.

I really should of read the Rustonomicon from the start instead of assuming that it covered more advanced topics that wouldn't be immediately relevant to me. It explains a ton of stuff that the rust manual/guide glosses over and a lot of it turned up in my programming almost immediately out of the gate. So I'm going to step back and work through the Rustonomicon until I feel that I have a much more solid grasp on things and try again.

Linear Zoetrope
Nov 28, 2011

A hero must cook
Uh... you should be able to depend on yanked crates, right? That's why the whole yanking system exists? Some of my old code broke due to the ncollide package getting yanked and split into two separate crates for 2D and 3D. The crates.io registry errors saying it's not able to find it which is a problem because I'm trying to keep the code as similar is possible (due to study replication guidelines for an academic paper yadda yadda). I upgraded to 0.19 without too much trouble but there's always that bit of nervousness that changing your code changed the dynamics a bit.

I mean, this is academic, nobody is gonna bother replicating it anyway but in principle.

Linear Zoetrope fucked around with this message at 22:25 on May 24, 2019

Vanadium
Jan 8, 2005

afaik you're supposed to be able to keep using a Cargo.lock that already has those yanked revisions baked into it, but you won't be able to get there anymore from just a Cargo.toml.

Either way that that seems like a weird reason to yank a crate.

For replication, maybe you could find the right git revision corresponding to the yanked release and depending on that directly instead of going through cargo.

necrotic
Aug 2, 2005
I owe my brother big time for this!

Vanadium posted:

For replication, maybe you could find the right git revision corresponding to the yanked release and depending on that directly instead of going through cargo.

If you go the route of pinning to a specific SHA you should probably clone it somewhere you control, lest the owner decides to nuke some history or the repo.

xtal
Jan 9, 2011

by Fluffdaddy
You know how "the cloud is just someone else's server?" crates.io, rubygems.org, npm.org, clojars.org, whatever, is just someone else's repository.

xtal fucked around with this message at 22:40 on May 29, 2019

Khorne
May 1, 2002
(1) I'm looking to implement websockets in a project.

I started using actix to do it, but the actor model seems like total overkill and due to the nature of the project it would just have the actor acting as a thin translation layer.

I'm debating switching to ws-rs. I'm wondering if anyone here has opinions either way or could list some pros and cons.

This is a weekend project, and I am learning rust for the sake of learning it. Becoming more familiar with the common mangling of the actor model present in modern libraries is a plus to me. I would like to reuse this portion of the project in future projects. I've worked with actors before, although a more pure implementation and not in such a high level way. I am not particularly familiar with how actix or rust work under the hood, and it seems like this is bottlenecking me. Stumbling through learning language features at the same time is also slowing me down I suppose.

With ws-rs I could finish the websocket side of the project in a few hours. With actix, I've dumped significant time in already and I feel like I'm learning a library with ambiguous benefits or perhaps no benefits over using the other library in an effective way. I'm really into parallel anything, so working with actors in a 'modern' language seemed like a good fit. After diving in it has just felt like I'd chosen the wrong tool for the project. But perhaps not the wrong tool for learning, because getting used to actix could translate fairly well to other tools I may use professionally.


(2) A bit of a tangent, but are there any good resources for dealing with threading, shared memory, vector instruction sets, memory structure, etc using rust? A guide to doing lower level things in the language is what I'm looking for. I haven't looked into this yet so the docs may be sufficient. I have a decent background in asm/c/c++/opencl/cuda so I'm no stranger to what's happening at a low level. I just don't know anything about doing these things in rust.



Rust has been pleasant and I haven't ran into any issues with how it works. It seems to be a language structured similarly to my current understanding of best practices, although some of the lower level details are a bit unclear to me.

My only complaint is RLS frequently breaks and makes the IDE/editor trip over itself. I've ran into issues building that required closing my IDE then reopening it - but these issues building were effecting unrelated command prompt windows as well not just the ide. Nothing would build until closing the IDE. The compiler would literally hang indefinitely on the last step on a trivial project that builds in under 1s normally.

Khorne fucked around with this message at 19:01 on May 31, 2019

DONT THREAD ON ME
Oct 1, 2002

by Nyc_Tattoo
Floss Finder

1. Yeah, I think you should absolutely stick with ws-rs for exactly the reasons you mentioned. Or maybe write your own websockets implementation. If you want to get more serious I'd consider tokio, which will handle (2) for you.

2. You probably want the nomicon, https://doc.rust-lang.org/nomicon/ IMO rust docs do a good job of educating people about the happy path but I've had a really hard time learning the lower level/unsafe details (this is definitely partly due to my own inexperience with lower level languages, rust was my first).

3. RLS is the biggest disaster in Rust ATM. I have faith that it will get there eventually but it's just not usable and it should not be recommended to new users. Intellij rust plugin is way way way way way way, way way better.

DONT THREAD ON ME fucked around with this message at 17:47 on May 31, 2019

netcat
Apr 29, 2008
If I want to cross compile rust (to ARM), is https://github.com/rust-embedded/cross what I want or are there other/better approaches?

taqueso
Mar 8, 2004


:911:
:wookie: :thermidor: :wookie:
:dehumanize:

:pirate::hf::tinfoil:

netcat posted:

If I want to cross compile rust (to ARM), is https://github.com/rust-embedded/cross what I want or are there other/better approaches?

That's what you want. Install and enable docker, run 'cargo install cross' and then 'cross <cargo command like build> --target <target>'. It's fairly magical, I was very impressed with how well it worked.

Except, I had to use the version from this PR: https://github.com/rust-embedded/cross/pull/251
Because without it, it doesn't support SELinux. :/

e: so the install command is 'cargo install --git https://github.com/cyplo/cross/ --branch selinux-support cross'

taqueso fucked around with this message at 18:20 on Jun 13, 2019

netcat
Apr 29, 2008

taqueso posted:

That's what you want. Install and enable docker, run 'cargo install cross' and then 'cross <cargo command like build> --target <target>'. It's fairly magical, I was very impressed with how well it worked.

Except, I had to use the version from this PR: https://github.com/rust-embedded/cross/pull/251
Because without it, it doesn't support SELinux. :/

e: so the install command is 'cargo install --git https://github.com/cyplo/cross/ --branch selinux-support cross'

Alright, cool. I'm looking to learn rust by writing little services for our embedded platform at work so I'm gonna give this a go.

Progressive JPEG
Feb 19, 2003

Getting caught up on accumulating values into a map member and then returning them in bulk after a sufficient number of entries have been accumulated, at which point the map would also be reset for a new batch of input.

I could just do a clone of the map for the output. However, I don't need to access the flushed map after its been outputted, so the copy would in theory be unnecessary. Instead I'd like to swap the populated map with a new empty map and then output the populated map before resuming collection of new entries. I was thinking that would look something like this:

code:
// swap self.map with new HashMap, output former self.map
let (output, self.map) = (self.map, HashMap::new())
return Ok(output);
However this fails syntax on the first half of the "let" statement where I'm attempting to do the swap. Apparently it dislikes me doing this with a member variable of "self"? Same story with this slightly different version of the same thing:

code:
let mut output = HashMap::new();
(output, self.headers) = (self.headers, output);
return Ok(output);

repiv
Aug 13, 2009

Sounds like you want mem::swap

code:
use std::mem;

[...]

let mut output = HashMap::new();
mem::swap(&mut self.map, &mut output);
Ok(output)

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today
Or, more concisely, mem::replace(&mut self.map, HashMap::new()).

Progressive JPEG
Feb 19, 2003

Aha yep that's what I was missing. I had seen that when searching around, but passed it over because based on the "mem" package name I thought it'd be physically copying between the two variables as if they were memory buffers.

repiv
Aug 13, 2009

The standard library has both - mem::swap/mem::replace do it safely through references, and ptr::swap/ptr::replace do it unsafely through raw pointers.

Progressive JPEG
Feb 19, 2003

aaaaAAAAAAAAAAA

code:
error[E0277]: `T` cannot be sent between threads safely
  --> src/bin/server.rs:84:5
   |
84 |     tokio::spawn(session);
   |     ^^^^^^^^^^^^ `T` cannot be sent between threads safely
   |
   = help: within `tokio_io::_tokio_codec::framed::Framed<T, tokio_scgi::SCGICodec>`, the trait `std::marker::Send` is not implemented for `T`
   = help: consider adding a `where T: std::marker::Send` bound
   = note: required because it appears within the type `tokio_io::_tokio_codec::framed::Fuse<T, tokio_scgi::SCGICodec>`
   = note: required because it appears within the type `tokio_io::_tokio_codec::framed_write::FramedWrite2<tokio_io::_tokio_codec::framed::Fuse<T, tokio_scgi::SCGICodec>>`
   = note: required because it appears within the type `tokio_io::_tokio_codec::framed_read::FramedRead2<tokio_io::_tokio_codec::framed_write::FramedWrite2<tokio_io::_tokio_codec::framed::Fuse<T, tokio_scgi::SCGICodec>>>`
   = note: required because it appears within the type `tokio_io::_tokio_codec::framed::Framed<T, tokio_scgi::SCGICodec>`
   = note: required because of the requirements on the impl of `std::marker::Send` for `futures::sync::bilock::Inner<tokio_io::_tokio_codec::framed::Framed<T, tokio_scgi::SCGICodec>>`
   = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<futures::sync::bilock::Inner<tokio_io::_tokio_codec::framed::Framed<T, tokio_scgi::SCGICodec>>>`
   = note: required because it appears within the type `futures::sync::bilock::BiLock<tokio_io::_tokio_codec::framed::Framed<T, tokio_scgi::SCGICodec>>`
   = note: required because it appears within the type `futures::stream::split::SplitSink<tokio_io::_tokio_codec::framed::Framed<T, tokio_scgi::SCGICodec>>`
   = note: required because it appears within the type `std::option::Option<futures::stream::split::SplitSink<tokio_io::_tokio_codec::framed::Framed<T, tokio_scgi::SCGICodec>>>`
   = note: required because it appears within the type `futures::sink::send_all::SendAll<futures::stream::split::SplitSink<tokio_io::_tokio_codec::framed::Framed<T, tokio_scgi::SCGICodec>>, futures::stream::and_then::AndThen<futures::stream::split::SplitStream<tokio_io::_tokio_codec::framed::Framed<T, tokio_scgi::SCGICodec>>, fn(tokio_scgi::SCGIRequest) -> std::boxed::Box<(dyn futures::future::Future<Error = std::io::Error, Item = tokio_scgi::SCGIRequest> + std::marker::Send + 'static)> {respond}, std::boxed::Box<(dyn futures::future::Future<Error = std::io::Error, Item = tokio_scgi::SCGIRequest> + std::marker::Send + 'static)>>>`
   = note: required because it appears within the type `futures::future::chain::Chain<futures::sink::send_all::SendAll<futures::stream::split::SplitSink<tokio_io::_tokio_codec::framed::Framed<T, tokio_scgi::SCGICodec>>, futures::stream::and_then::AndThen<futures::stream::split::SplitStream<tokio_io::_tokio_codec::framed::Framed<T, tokio_scgi::SCGICodec>>, fn(tokio_scgi::SCGIRequest) -> std::boxed::Box<(dyn futures::future::Future<Error = std::io::Error, Item = tokio_scgi::SCGIRequest> + std::marker::Send + 'static)> {respond}, std::boxed::Box<(dyn futures::future::Future<Error = std::io::Error, Item = tokio_scgi::SCGIRequest> + std::marker::Send + 'static)>>>, futures::future::result_::FutureResult<(), ()>, [closure@src/bin/server.rs:78:68: 83:6]>`
   = note: required because it appears within the type `futures::future::then::Then<futures::sink::send_all::SendAll<futures::stream::split::SplitSink<tokio_io::_tokio_codec::framed::Framed<T, tokio_scgi::SCGICodec>>, futures::stream::and_then::AndThen<futures::stream::split::SplitStream<tokio_io::_tokio_codec::framed::Framed<T, tokio_scgi::SCGICodec>>, fn(tokio_scgi::SCGIRequest) -> std::boxed::Box<(dyn futures::future::Future<Error = std::io::Error, Item = tokio_scgi::SCGIRequest> + std::marker::Send + 'static)> {respond}, std::boxed::Box<(dyn futures::future::Future<Error = std::io::Error, Item = tokio_scgi::SCGIRequest> + std::marker::Send + 'static)>>>, std::result::Result<(), ()>, [closure@src/bin/server.rs:78:68: 83:6]>`
   = note: required by `tokio::executor::spawn`

Linear Zoetrope
Nov 28, 2011

A hero must cook
At least usually when you get terrifying type stuff like that, you can figure out what's going on by looking at the first couple and last couple lines of context.

Unlike macro expansion, debugging macro expansion is hell even with the tools developed for it.

Progressive JPEG
Feb 19, 2003

Yeah in that case the fix was the second line: "help: consider adding a `where T: std::marker::Send` bound"

But I definitely had flashbacks to C++ template compilation errors and it wasn't a good feeling

Linear Zoetrope
Nov 28, 2011

A hero must cook
I think the most confusing errors are when you get "the trait does not live long enough". Especially when triggered from a derive proc macro. "The trait does not live long enough" is honestly a really bad error message since it implies that like... Traits can be dynamically added or removed from concrete types (IDK if they've improved the error since I got it). Also unluckily, it's an error that you only tend to get when you're new to Rust, because once you're experienced you've learned the language enough to automatically design in a way that it rarely comes up. (The only time I see it anymore is when wrestling with third party frameworks).

Beamed
Nov 26, 2010

Then you have a responsibility that no man has ever faced. You have your fear which could become reality, and you have Godzilla, which is reality.


Anyone give the RLS a shot recently? Some of CLion's weirdness has begun getting to me.

gonadic io
Feb 16, 2011

>>=

Beamed posted:

Anyone give the RLS a shot recently? Some of CLion's weirdness has begun getting to me.

It has not improved since the 1.0 release. I tried it when vscode's remote and docker stuff came to insider.

The biggest issue, by far, that I have with it is: https://github.com/rust-lang/rls/issues/352
i.e. code completion only works on projects which type check on things which have type annotations - there is zero type inference.

Although you're right in clion, I'm unable to use any IDE support on structs/functions defined in declarative macros even on the new macro engine. I'm not sure what's going on, I'm sure it used to work before.

E: I figured out why this was happening, jetbrains' rust plug can't handle path dependences. Bring on Rls 2.0

gonadic io fucked around with this message at 15:52 on Jul 12, 2019

mystes
May 31, 2006

OK, I think I may actually hate rust now.

The problem I'm having is that with non-lexical lifetimes, if there's a variable you borrowed earlier and you think you're done with it so it's ok to try to do something else that will cause it to be borrowed again but you accidentally still have a reference to something lying around that is causing the variable to still be borrowed, the compiler doesn't say "hey, you have this other variable here causing your first variable to be borrowed," it just tells you "you already have it borrowed so you can't borrow it again dumbass" and then it's up to you to try to figure out what might be causing it to still be borrowed by looking at the lifetimes in the type signatures of everything.

Like it was totally my fault since what I was doing didn't actually make sense (I tried to use something after it wouldn't make sense to do so) so I guess the compiler was right, but I wish it could actually tell me that.

mystes fucked around with this message at 00:50 on Jul 13, 2019

taqueso
Mar 8, 2004


:911:
:wookie: :thermidor: :wookie:
:dehumanize:

:pirate::hf::tinfoil:

I'm experiencing semantic satiation for 'borrowed' now, thanks.

gonadic io
Feb 16, 2011

>>=

mystes posted:

OK, I think I may actually hate rust now.

The problem I'm having is that with non-lexical lifetimes, if there's a variable you borrowed earlier and you think you're done with it so it's ok to try to do something else that will cause it to be borrowed again but you accidentally still have a reference to something lying around that is causing the variable to still be borrowed, the compiler doesn't say "hey, you have this other variable here causing your first variable to be borrowed," it just tells you "you already have it borrowed so you can't borrow it again dumbass" and then it's up to you to try to figure out what might be causing it to still be borrowed by looking at the lifetimes in the type signatures of everything.

Like it was totally my fault since what I was doing didn't actually make sense (I tried to use something after it wouldn't make sense to do so) so I guess the compiler was right, but I wish it could actually tell me that.

I have resorted to replacing lines of code with unimplemented!() and seeing which was invisibly holding onto a borrow, I agree. FWIW if you open an issue complaining that this error message isn't clear it'll be taken seriously.

e: and/or just replacing all usages with a clone. Life's too short to zero copy.

Anarchist Mae
Nov 5, 2009

by Reene
Lipstick Apathy
Anyone here working on any crates? I'm working on these:

https://crates.io/crates/glue
https://crates.io/crates/etch
https://crates.io/crates/pose
https://crates.io/crates/css-modules

Also, yeah, lifetime stuff can be hell, but there are tools that make more complicated systems pretty easy, if a little more verbose, but then that's just Rust.

For example, if you've ever tried to implement a tree data type in rust, you know it's not as easy as in a memory managed language, especially so if you need the children to know what their parent nodes are.

But you can use an Arc<RefCell<T>>:

https://gist.github.com/measlytwerp/f6fcf48be63fb1e2378cb3c4a916c7bd

Dominoes
Sep 20, 2007

I'm working on a WASM frontend crate, seed

repiv
Aug 13, 2009

Measly Twerp posted:

For example, if you've ever tried to implement a tree data type in rust, you know it's not as easy as in a memory managed language, especially so if you need the children to know what their parent nodes are.

Arenas are another option provided you don't need to drop individual nodes. Nodes allocated from the same arena all have the same lifetime, so they can freely hold references to each other, circular references, whatever, the compiler doesn't care as long as the arena lives long enough.

e.g. https://docs.rs/typed-arena/1.4.1/typed_arena/#safe-cycles

repiv fucked around with this message at 15:39 on Jul 13, 2019

gonadic io
Feb 16, 2011

>>=
I made https://crates.io/crates/form and https://crates.io/crates/arduino_mkrzero when I was working on embedded stuff, but that's fallen a little down to the wayside compared to messing around with utilities for Dominions 5: a discord bot and then a few other assorted bits here and there.

I tried making a twitter app thing, that you'd log into and it'd block people for you but got a bit too turned around. I got oauth2 working, just about, but then got too paralysed about persistency and scaling
This is as far as I got: https://github.com/djmcgill/de-list-server

gonadic io fucked around with this message at 17:56 on Jul 13, 2019

Progressive JPEG
Feb 19, 2003

I implemented support for SCGI clients/servers a couple weeks ago. Wanted to run nginx as a frontend to a rust app and noticed there wasn't a rust SCGI implementation for this yet. Spent way more time just getting the example tokio client/server to work than on the codec itself. Tokio has a real problem with plentiful examples floating around from months ago that are already out of date and unusable.

Is there a way to update the README content included on crates.io without cutting a whole new release? I added some README content in the repo but there hasn't been any need to change the code. The sole image link in the crate README has stopped rendering as well, because they apparently just link back to the repo master for images rather than importing them. "Immutable" my rear end.

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today
I maintain Quinn, a QUIC implementation with a futures-based high level interface (QUIC is a very cool upcoming network protocol being standardized by the IETF, it's kind of a best-of-both-worlds-and-then some thing when compared to TLS+TCP and UDP), and openxrs, a binding to the excellent provisional OpenXR API for virtual reality applications. I also have various low-level real-time graphics crates, and contribute to a bunch of other stuff like tokio and ash.

Progressive JPEG posted:

Is there a way to update the README content included on crates.io without cutting a whole new release? I added some README content in the repo but there hasn't been any need to change the code. The sole image link in the crate README has stopped rendering as well, because they apparently just link back to the repo master for images rather than importing them. "Immutable" my rear end.
Sadly you have to make a patch release for metadata updates. Fortunately this is easy and harmless.

Ralith fucked around with this message at 05:30 on Jul 14, 2019

Progressive JPEG
Feb 19, 2003

Ralith posted:

Sadly you have to make a patch release for metadata updates. Fortunately this is easy and harmless.

Eh I'll wait until the code actually needs an update the next time tokio makes a breaking API change, which will probably be in a month or two assuming we don't have another year of async/await bikeshedding to look forward to. No need to bend over backwards for a package management system that doesn't know what immutable means. But lesson learned: only provide packages with minimal stub content that links to the real docs.

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

QUIC is great and I’m glad a cool dude is bringing it to Rust!

ewe2
Jul 1, 2009

Just starting to teach myself Rust in VS code but I'm slightly confused by (I'm assuming here) RLS deciding that braces () in a macro are bad and they should be {} ?! Any ideas where to configure that behaviour?

Adbot
ADBOT LOVES YOU

gonadic io
Feb 16, 2011

>>=

ewe2 posted:

Just starting to teach myself Rust in VS code but I'm slightly confused by (I'm assuming here) RLS deciding that braces () in a macro are bad and they should be {} ?! Any ideas where to configure that behaviour?

What do you mean? I've not seen that before, can you post a snippet or two showing the behavior?

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