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


Double post, am I doing Rust right if almost all my mods end up being "pub mod"? Not sure how to expose, e.g., a crate one mod exposes without at least making it pub.

Adbot
ADBOT LOVES YOU

Linear Zoetrope
Nov 28, 2011

A hero must cook

Beamed posted:

Double post, am I doing Rust right if almost all my mods end up being "pub mod"? Not sure how to expose, e.g., a crate one mod exposes without at least making it pub.

External crates are almost always put in lib.rs/main.rs. The only real exceptions are generated code that can't always rely on a dependency being available in a given location (and thus generate an extern crate declaration in the generated block).

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.


Linear Zoetrope posted:

External crates are almost always put in lib.rs/main.rs. The only real exceptions are generated code that can't always rely on a dependency being available in a given location (and thus generate an extern crate declaration in the generated block).

Which raises my question, I guess - I have extern crates which bring in dependencies for my controller/views on a given platform, but ideally later I'll have a second controller available with completely different dependencies. Things are definitely much nicer if I reference these in main for now, but I'd ideally like platform-specific view/controller to go to the specific controller, and so only bring in crates there. Guess it's a matter of if I care enough to create wrappers for those dependencies, huh..

Linear Zoetrope
Nov 28, 2011

A hero must cook

Beamed posted:

Which raises my question, I guess - I have extern crates which bring in dependencies for my controller/views on a given platform, but ideally later I'll have a second controller available with completely different dependencies. Things are definitely much nicer if I reference these in main for now, but I'd ideally like platform-specific view/controller to go to the specific controller, and so only bring in crates there. Guess it's a matter of if I care enough to create wrappers for those dependencies, huh..

I mean, you can do that, you just have to make sure that the crate is only referenced in child crates of the one you import it from. No need for pub then.

Something like

code:
unix/mod.rs <-- extern crate here
unix/controller.rs

windows/mod.rs <-- extern crate here
windows/controller.rs
And so on.

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
Relatedly, in that type of situation I like to do
code:
#[cfg(target_os = "windows")]
#[path="windows/mod.rs"]
mod platform;
#[cfg(target_os = "linux")]
#[path="linux/mod.rs"]
mod platform;
sort of thing, though you have to take considerable care to ensure the public APIs stay perfectly in sync if you don't enforce it with a trait or something.

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.


Linear Zoetrope posted:

I mean, you can do that, you just have to make sure that the crate is only referenced in child crates of the one you import it from. No need for pub then.

Something like

code:
unix/mod.rs <-- extern crate here
unix/controller.rs

windows/mod.rs <-- extern crate here
windows/controller.rs
And so on.



Ralith posted:

Relatedly, in that type of situation I like to do
code:
#[cfg(target_os = "windows")]
#[path="windows/mod.rs"]
mod platform;
#[cfg(target_os = "linux")]
#[path="linux/mod.rs"]
mod platform;
sort of thing, though you have to take considerable care to ensure the public APIs stay perfectly in sync if you don't enforce it with a trait or something.

Oh wow, this is perfect. Thanks guys!

Love Stole the Day
Nov 4, 2012
Please give me free quality professional advice so I can be a baby about it and insult you
The Rust youtube channel has just uploaded a bunch of lectures from some recent conference called Fosdem: https://www.youtube.com/channel/UCaYhcUwRBNscFNUKTjgPFiA/videos

TalkLittle
Jun 23, 2004

Love Stole the Day posted:

The Rust youtube channel has just uploaded a bunch of lectures from some recent conference called Fosdem: https://www.youtube.com/channel/UCaYhcUwRBNscFNUKTjgPFiA/videos

https://www.youtube.com/watch?v=fJ-6wsn1bZg "Qt GUIs with Rust" gives me hope for Rust GUIs.

I'm currently using Gtk-rs for something I'd rather do with Piston/Conrod, because I couldn't get any of the Glutin/SDL2 based Piston windows to load on Intel Graphics. Also on a different machine, drawing bitmap textures was giving me weirdly desaturated colors, but drawing the same thing with GDK Pixbufs works just fine.

Glad to see Qt up and coming as another option for Rust, even though this guy's approach still involves a bit of C++/JSON boilerplate.

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.


So am I missing something with the IntelliJ plugin? Tried it out again after everyone raved about it, but it still forces me to run cargo manually to see if I have any compiler errors. Do I accidentally have a setting that removes IntelliJ's underlining compiler/syntax errors or something?

VS Code is still pretty cool but I miss the heavy IDE stuff sometimes.

TalkLittle
Jun 23, 2004

I've had similar experiences with IntelliJ. At least recent versions of the Rust plugin seem to have memory leaks and slowdowns, and it doesn't show all the errors or do proper syntax completion from crates.

It's been a while since I tried Sublime Text with Rust, but IIRC that actually worked better with inline error checking.

Arcsech
Aug 5, 2008

Beamed posted:

So am I missing something with the IntelliJ plugin? Tried it out again after everyone raved about it, but it still forces me to run cargo manually to see if I have any compiler errors. Do I accidentally have a setting that removes IntelliJ's underlining compiler/syntax errors or something?

VS Code is still pretty cool but I miss the heavy IDE stuff sometimes.

I only get some, but not all, errors showing up inside of IntelliJ. Like it’ll usually catch typos and most type mismatches, but I don’t think it’s ever caught borrow checker issues without invoking the compiler.

rufius
Feb 27, 2011

Clear alcohols are for rich women on diets.

Beamed posted:

So am I missing something with the IntelliJ plugin? Tried it out again after everyone raved about it, but it still forces me to run cargo manually to see if I have any compiler errors. Do I accidentally have a setting that removes IntelliJ's underlining compiler/syntax errors or something?

VS Code is still pretty cool but I miss the heavy IDE stuff sometimes.

Ditto. I’ve settled into a good workflow with Sublime Text and the RustEnhanced plugin. It’ll be nice once JetBrains has a full IDE though.

gonadic io
Feb 16, 2011

>>=
I've loved intellij's support but it's not entirely cargo free no.
Still a million times better than vs code and RLS though.

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.


gonadic io posted:

I've loved intellij's support but it's not entirely cargo free no.
Still a million times better than vs code and RLS though.

VS code shows me compiler/syntax errors immediately, lets me ctrl+click into library code to read some APIs, in-built terminal, and is pretty. Am I missing something from IntelliJ that provides me even the first? Honestly asking because I really felt like I was missing something.

Fergus Mac Roich
Nov 5, 2008

Soiled Meat

gonadic io posted:

I've loved intellij's support but it's not entirely cargo free no.
Still a million times better than vs code and RLS though.

Visual debugging seems to work very well in VS Code.

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

Programming Rust is in the latest Humble Bundle, FYI.

DONT THREAD ON ME
Oct 1, 2002

by Nyc_Tattoo
Floss Finder

Beamed posted:

VS code shows me compiler/syntax errors immediately,
??? this definitely works for me. Maybe RLS + VSCode is better but I've never had it not just continually crash on me so I'm not sure what it's like.





quote:

lets me ctrl+click into library code to read some APIs,
cmd+b?

quote:

in-built terminal
intellij has this feature, I'm not sure how to use it because I prefer to use a stand aside terminal

i have no doubt that RLS will be the way to go eventually but it wasn't there last time I tried it (admittedly, around 6 months ago, haven't been doing much rust lately).

DONT THREAD ON ME fucked around with this message at 02:50 on Feb 14, 2018

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.


MALE SHOEGAZE posted:

??? this definitely works for me. Maybe RLS + VSCode is better but I've never had it not just continually crash on me so I'm not sure what it's like.




Nope, don't get this.


FAKEDIT: By the time I finished adding that to imgur and writing this post, it finally showed a red line. That.. I dunno, took awhile to recognize when I added the semicolon too. Doesn't spot the type error, either way.

MALE SHOEGAZE posted:


cmd+b?

intellij has this feature, I'm not sure how to use it because I prefer to use a stand aside terminal

i have no doubt that RLS will be the way to go eventually but it wasn't there last time I tried it (admittedly, around 6 months ago, haven't been doing much rust lately).


Didn't say that IntelliJ didn't have these features, just meant to say VSCode supports the most necessary things pretty quickly.

REALEDIT: Perhaps ironically, I feel like IntelliJ will be the way to go in the future; the more fully fleshed out features it provides will be better than I think RLS will support.

DONT THREAD ON ME
Oct 1, 2002

by Nyc_Tattoo
Floss Finder

Beamed posted:

Nope, don't get this.


FAKEDIT: By the time I finished adding that to imgur and writing this post, it finally showed a red line. That.. I dunno, took awhile to recognize when I added the semicolon too. Doesn't spot the type error, either way.



Didn't say that IntelliJ didn't have these features, just meant to say VSCode supports the most necessary things pretty quickly.

REALEDIT: Perhaps ironically, I feel like IntelliJ will be the way to go in the future; the more fully fleshed out features it provides will be better than I think RLS will support.

That's weird friend, I dunno. Works on my machine, I guess!

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.


MALE SHOEGAZE posted:

That's weird friend, I dunno. Works on my machine, I guess!

Yeah, it's good to know that I am just missing something, haha.

Skier
Apr 24, 2003

Fuck yeah.
Fan of Britches

Subjunctive posted:

Programming Rust is in the latest Humble Bundle, FYI.

I've written libraries in Rust since 1.0 and this book taught me a lot, just halfway through reading it.

Linear Zoetrope
Nov 28, 2011

A hero must cook
Has anyone else had issues getting std::fs::remove_dir_all working on Windows? I get OS error 5 by doing something as simple as creating a directory tree and trying to remove it. I've been resorting to a #[cfg(windows)] patch function that just delegates to spawning a command running rmdir but that's obviously not... ideal.

Edit: I figured it out, I was using the created tree to clone a git repository into and git was setting permissions weirdly. Had to use walkdir to manually set the cloned files to not be readonly :shrug:.

Linear Zoetrope fucked around with this message at 04:19 on Feb 21, 2018

Aurium
Oct 10, 2010
Github recently removed TLS 1.0 and 1.1 support. Windows 7's default behavior is not to support anything past TLS 1.0

The combination breaks cargo for a while, unless you install a patch.

Microsoft Article

They're currently working on making the generated error more descriptive of this particular issue.

https://github.com/rust-lang/cargo/issues/5066

geonetix
Mar 6, 2011


If you’re still not able to support TLS 1.1 or up you bloody well deserve to be left behind. Especially when you’re trying to be a “modern” packaging system

Aurium
Oct 10, 2010
It's not that it can't, it's that the defaults that Windows 7 supplies, even after installing the system update to support recent tls versions, does not actually enable it.

https://github.com/libgit2/libgit2/issues/4546
https://github.com/libgit2/libgit2/pull/4550

xtal
Jan 9, 2011

by Fluffdaddy

geonetix posted:

If you’re still not able to support TLS 1.1 or up you bloody well deserve to be left behind. Especially when you’re trying to be a “modern” packaging system

This is correct when you replace "packaging system" with "operating system"

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed
I think when an OS's mainstream support period has ended you can safely say it's no longer trying to be a modern OS.

EkardNT
Mar 31, 2011
I'm learning Rust and the borrow checker is beating me. I want to return a struct from a function, where the struct owns Stdout and StdoutLock objects that live as long as the struct itself. I'm pretty sure this means I need to heap-allocate the stdout objects, so Box needs to be involved somehow. Can someone help me understand what I need to do to get this to work?

code:
struct Foo<'a> {
    stdout: Box<Stdout>,
    writer: Box<StdoutLock<'a>>
}

fn make_foo<'a>() -> Foo<'a> {
    let stdout : Box<Stdout> = Box::new(std::io::stdout());
    let writer : Box<StdoutLock> = Box::new(stdout.lock());
    Foo {
        stdout,
        writer
    }
}
This fails miserably.

code:
error[E0597]: `*stdout` does not live long enough
   --> src/bin/generate.rs:124:45
    |
124 |     let writer : Box<StdoutLock> = Box::new(stdout.lock());
    |                                             ^^^^^^ borrowed value does not live long enough
...
129 | }
    | - borrowed value only lives until here
    |
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 122:1...
   --> src/bin/generate.rs:122:1
    |
122 | / fn make_foo<'a>() -> Foo<'a> {
123 | |     let stdout : Box<Stdout> = Box::new(std::io::stdout());
124 | |     let writer : Box<StdoutLock> = Box::new(stdout.lock());
125 | |     Foo {
...   |
128 | |     }
129 | | }
    | |_^
Full disclosure, what I'm actually trying to do is write a CLI program which can send its output either to standard out or a file, depending on a flag the user calls the program with. My idea is to have an enum which represents the choice of destination, where each enum variant maintains all the information needed to write to the appropriate output.

code:
// This isn't valid Rust but hopefully communicates what I'm going for.
enum OutputDest {
    StdOutput {
        stdout: std::io::Stdout,
        writer: std::io::BufWriter<std::io::StdoutLock>
    },
    File {
        writer: std::io::BufWriter<std::io::File>
    }
}

impl OutputDest {
    fn write(&mut self, data: &[u8]) {
        match self {
            OutputDest::StdOutput { writer } => writer.write(data),
            OutputDest::File { writer } => writer.write(data)
        }
    }
}

eth0.n
Jun 1, 2012

EkardNT posted:

I'm learning Rust and the borrow checker is beating me. I want to return a struct from a function, where the struct owns Stdout and StdoutLock objects that live as long as the struct itself. I'm pretty sure this means I need to heap-allocate the stdout objects, so Box needs to be involved somehow. Can someone help me understand what I need to do to get this to work?

Are you sure you need the Lock? You can write to Stdout directly, it just might get interleaved if another part of your program is also writing to it. Is this a concern?

I'm not sure how to do this with StdoutLock, but if you only need Stdout, you don't need to Box it.

Mr. Glass
May 1, 2009
alternatively, make the thing you plan to pass OutputDest to generic for any std::io::Write instead

Dominoes
Sep 20, 2007

Yo dudes; learning Rust, and struggling with the borrow checker and unexpected ungulates.

Code:
Rust code:
pub fn trailing_ed(contents: String) -> String {
    // Change trailing ed to D, trailing es to S etc.
    let tail_letters = ["d", "x", "s", "l"];

    let mut result = &contents;
    // Could handle this loop with a more complex regex instead.
    for letter in tail_letters.iter() {
        let re_str = r"(e".to_string() + letter + r")\s+";
        let re = Regex::new(&re_str).unwrap();
        
        // let replacement = &letter.to_uppercase();
        result = re.replace_all(result, "test");

    }

    result.to_string()
}
Error:
code:
error[E0308]: mismatched types
  --> src\to_shorthand.rs:37:18
   |
37 |         result = re.replace_all(result, "test");
   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found enum `std::borrow::Cow`
   |
   = note: expected type `&std::string::String`
              found type `std::borrow::Cow<'_, str>`
I dug a bit on cows; tried to match their Borrowed and Owned enum fields, with no luck. The official example:
code:
let re = Regex::new(r"(?P<y>\d{4})-(?P<m>\d{2})-(?P<d>\d{2})").unwrap();
let before = "2012-03-14, 2013-01-01 and 2014-07-05";
let after = re.replace_all(before, "$m/$d/$y");
assert_eq!(after, "03/14/2012, 01/01/2013 and 07/05/2014");
implies exploring the cow shouldn't be required. Something involving my loop is causing my code to break while the example doesn't.

Lime
Jul 20, 2004

The example works because the type of "after" is inferred, so it just is a Cow<str>. In your code, "result" has the type &String, which is inferred from where it's initialized, so you can't just assign the Cow to it. And matching isn't helping because Cow holds either a &str, which you'd have to turn into a new String, or else a String that is about to be dropped after the current iteration of the for loop ends. The problem is that "result" can't refer to something it is going to outlive.

Basically, you should change result to be a String itself because something has to actually own the intermediate, partially processed strings. When updating result, you could just blindly call into_owned() on the Cow from replace_all(). But this is wasteful as it will create a new String even when nothing got replaced, ie, when the Cow is Borrowed. So you can ignore that case and only look at when Cow is Owned, in which case you can just move from the String it holds:

code:
    
    let mut result = contents;
    for letter in tail_letters.iter() {
        let re_str = r"(e".to_string() + letter + r")\s+";
        let re = Regex::new(&re_str).unwrap();
	if let Cow::Owned(s) = re.replace_all(&result, "test") { 
            result = s; 
        }
    }

Dominoes
Sep 20, 2007

Thank you; that explanation and code sorted it out entirely; needed to dissect the cow. Related: Now I'm tackling out the uppercase-conversion (Replaced by "test" in my previous example.

After changing the tail_letters iterator to chars instead of strings, this works:
code:
        let replacement: &str = &(letter.to_uppercase().to_string());

        if let Cow::Owned(s) = re.replace_all(&result, replacement) {
This does not:
code:
	// A string?
        let replacement = letter.to_uppercase().to_string();

	// converting the string to &str with &
        if let Cow::Owned(s) = re.replace_all(&result, &replacement) {
Nor does this:
code:
        let replacement = &(letter.to_uppercase().to_string());

        if let Cow::Owned(s) = re.replace_all(&result, replacement) {
Error:
code:
35 |         if let Cow::Owned(s) = re.replace_all(&result, replacement) {
   |                                   ^^^^^^^^^^^ the trait `for<'r, 's> std::ops::Fn<(&'r regex::Captures<'s>,)>` is not implemented for `std::string::String`
Why do I need to explicitly declare &str in this case? I added it to confirm that replacement was indeed an &str, yet it solved the problem.

Dominoes fucked around with this message at 00:39 on Mar 17, 2018

xtal
Jan 9, 2011

by Fluffdaddy
edit because I was wrong about this. But I think you are dealing with 3 different types. Count the `&` in each sample.

Dominoes
Sep 20, 2007

I'm counting one in each, excluding the type annotation. Ie to convert a String, as output by char.to_string(), to a &str, as required by re.replace_all.

Dominoes fucked around with this message at 01:19 on Mar 17, 2018

VikingofRock
Aug 24, 2008




Dominoes posted:

Why do I need to explicitly declare &str in this case? Shouldn't applying & automatically do that?

&replacement could be a &str or a &String (or a &&str or a &&String etc), and if this is the only time you use replacement rustc doesn't know which one to infer it as.
Looking at the docs for the regex crate, it looks like the signature for replace_all is generic in its second parameter:

pre:
pub fn replace_all<'t, R: Replacer>(
    &self, 
    text: &'t str, 
    rep: R
) -> Cow<'t, str>
So &replacement could be any type that impls Replacer. Since right now Replacer is only impl'd for &str, NoExpand, and any FnMut(&Captures) -> String, it seems like rustc should be able to deduce that the "correct" way to interpret &replacement is as &str, but right now it doesn't do that.

I think this may be intentional, since in the future someone could theoretically go add an impl of Replacer for String (or add an impl of FnMut(&Captures) -> String for String), which would cause your code to break. So my guess is Rust purposefully makes you type out the type here for that reason.

Dominoes
Sep 20, 2007

Thanks Viking - that makes sense!

Walh Hara
May 11, 2012
So, I'm an idiot and need help.

I want to get an array of length 64 of ChessCell objects. This should be really simple but it keeps giving compilation errors.

code:
    
let mut cells: [ChessCell; 64];
for i in 0..64 {
        cells[i] = ChessCell { ... };
    }
Gives the error "error[E0381]: use of possibly uninitialized variable: `cells`". I could make a vector and convert it to an array afterwards or initialise the array with incorrect objects, but both seem really dumb to me? Is there some trick?

I'm kinda used to functional programming so I also tried to:
1) make an array [0,1, 2, ..., 63]
2) apply a function to each value in the array (map)
3) put the result of this .map(f) in an array with the same fixed size
I'd expect this to be possible, but I'm having trouble with each of these three steps.

tazjin
Jul 24, 2015


I've spent the last two evenings looking at how to migrate a reasonably complex Rust system from error_chain to the new failure crate.

The system uses a bunch of external libraries (e.g. r2d2_postgres, rouille, serde of course, ...) and previously we used error_chain's foreign_links functionality to explicitly declare how all the possible errors that could occur would be converted into our error representations.

I considered that one of the major selling points of error handling in Rust: The compiler would be able to point out which foreign errors have not yet been "acknowledged" in the error handling strategy. It was still possible to then proceed to drop the errors on the floor, but dispatching different handling strategies on foreign & internal errors in the same way was trivial to do.

Now with failure everything gets shoved into a single, shared Error-type. Keeping information about what kind of error occured either requires littering the code with verbose .context(...) calls or using runtime reflection (:barf:) and - since almost every error is implicitly convertable to a failure - using ? now feels like working with a method that has throws Exception in its signature in Java.

To make things worse, errors from error_chain can actually not be converted to failures because they aren't Sync. This makes using libraries that have switched to failure somewhat painful from an error_chain based application.

This kind of "lets throw the types away!" dynlang bullshit should stay out of my Rust ecosystem :colbert:

Adbot
ADBOT LOVES YOU

Eela6
May 25, 2007
Shredded Hen

Walh Hara posted:

So, I'm an idiot and need help.

I want to get an array of length 64 of ChessCell objects. This should be really simple but it keeps giving compilation errors.

code:
    
let mut cells: [ChessCell; 64];
for i in 0..64 {
        cells[i] = ChessCell { ... };
    }
Gives the error "error[E0381]: use of possibly uninitialized variable: `cells`". I could make a vector and convert it to an array afterwards or initialise the array with incorrect objects, but both seem really dumb to me? Is there some trick?

I'm kinda used to functional programming so I also tried to:
1) make an array [0,1, 2, ..., 63]
2) apply a function to each value in the array (map)
3) put the result of this .map(f) in an array with the same fixed size
I'd expect this to be possible, but I'm having trouble with each of these three steps.

You've only declared the identifier, not initialized it. Unlike go, rust doesn't assume a default value for an identifier with a type but no initializer.

code:

let mut cells = [ChessCell{...}; 64]

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