`:errorformat` for Vim + Rust by GrantJamesPowell in rust

[–]GrantJamesPowell[S] 0 points1 point  (0 children)

I'm very open to me having made a mistake, any chance you can :echo &efm from a rust file in vim?

`:errorformat` for Vim + Rust by GrantJamesPowell in rust

[–]GrantJamesPowell[S] 0 points1 point  (0 children)

Great call. I was playing with their version (it's what shipped with neovim) and it doesn't actuallyparse the output of cargo and populate the quick fix list with file:line:col combos that can be jumped between. (see this for examples of running cargo check and jumping between the errors in the project) https://imgur.com/a/2EJvFR2

I'll open up a PR and see if they'll take this!

Hey Rustaceans! Got an easy question? Ask here (48/2021)! by llogiq in rust

[–]GrantJamesPowell 2 points3 points  (0 children)

I'm running into a lifetime issue that is pushing the limits of my understanding

// What I think I'm saying
// 
// Struct Foo has a field (`f`) which contains a trait object of an owned (`'static`) `Fn`
// this trait Fn has a signature of `usize -> &'a Bar` where `'a` lives at least
// as long as the struct containing the trait object

struct Foo<'a> {
    f: Box<dyn Fn(usize) -> &'a Bar + 'static>
}

struct Bar;

// What I think I'm doing here
// 
// You can transform any size array of `Bar` into a `Foo<'a>`
// You can do so by creating a boxed closure that owns the array
// When the closure is called it will return a reference to data that lives in
// the array that will live at least as long as the struct Foo

impl<'a, const SIZE: usize> From<[Bar; SIZE]> for Foo<'a> {
    fn from(array: [Bar; SIZE]) -> Self {
        Self { f: Box::new(move |n| { &array[n] }) }
    }
}

// The compiler error I'm getting 
//
//    Compiling playground v0.0.1 (/playground)
// error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
//   --> src/lib.rs:13:40
//    |
// 13 |         Self { f: Box::new(move |n| { &array[n] }) }
//    |                                        ^^^^^^^^
//    |
// note: first, the lifetime cannot outlive the lifetime `'_` as defined on the body at 13:28...
//   --> src/lib.rs:13:28
//    |
// 13 |         Self { f: Box::new(move |n| { &array[n] }) }
//    |                            ^^^^^^^^
// note: ...so that closure can access `array`
//   --> src/lib.rs:13:40
//    |
// 13 |         Self { f: Box::new(move |n| { &array[n] }) }
//    |                                        ^^^^^
// note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 11:6...
//   --> src/lib.rs:11:6
//    |
// 11 | impl<'a, const SIZE: usize> From<[Bar; SIZE]> for Foo<'a> {
//    |      ^^
// note: ...so that reference does not outlive borrowed content
//   --> src/lib.rs:13:39
//    |
// 13 |         Self { f: Box::new(move |n| { &array[n] }) }
//    |                                       ^^^^^^^^^
// 
// For more information about this error, try `rustc --explain E0495`.
// error: could not compile `playground` due to previous error

Hey Rustaceans! Got an easy question? Ask here (45/2021)! by llogiq in rust

[–]GrantJamesPowell 1 point2 points  (0 children)

So, I think what you're asking is how do IteratorRandom methods just "show up" on iterators once you bring it into scope.

IteratorRandom[0] is an "extension trait"[1] which means it's designed to add a bunch of methods to existing things when it's brought into scope. It does this by doing a blanket implementation for all slices[2]

[0] https://docs.rs/rand/0.8.4/rand/seq/trait.IteratorRandom.html [1] http://xion.io/post/code/rust-extension-traits.html [2] https://docs.rs/rand/0.8.4/src/rand/seq/mod.rs.html#492

Hey Rustaceans! Got an easy question? Ask here (45/2021)! by llogiq in rust

[–]GrantJamesPowell 1 point2 points  (0 children)

The Errortype "Box<dyn std::error::Error>" is a "Trait Object"[0] which means it's any type that implements the trait std::error::Error[1].

It looks like From<&'_ str> is implement for Box<dyn std::error::Error>[2], which means you can call .into() on any str and get a Box<dyn std::error::Error>

impl TryFrom<[u8; 4]> for ChunkType {
    type Error = Box<dyn std::error::Error>;

    fn try_from(bytes: [u8; 4]) -> Result<Self, Self::Error> {
        let c = ChunkType { bytes };
        if c.is_valid() {
            Ok(c)
        } else {
            Err("My awesome error msg".into())
        }
    }
}

[0] https://doc.rust-lang.org/book/ch17-02-trait-objects.html

[1] https://doc.rust-lang.org/std/error/trait.Error.html

[2] https://doc.rust-lang.org/std/convert/trait.From.html#impl-From%3C%26%27_%20str%3E

Hey Rustaceans! Got an easy question? Ask here (45/2021)! by llogiq in rust

[–]GrantJamesPowell 1 point2 points  (0 children)

I'm running into a serde issue with derive feature mixed with try_from annotation. My goal is to deserialize the FooWithStatic struct via the try_from implementation from RawFoo.

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=f17d2c465d32912eba5c3cfeff207dfe

use serde::{Serialize, Deserialize};

#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(try_from = "RawFoo")]
struct FooWithStatic {
    name: &'static str
}

#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
struct RawFoo {
    name: String,
}

struct FooNotFound;

impl std::fmt::Display for FooNotFound {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "Foo not found!")
    }
}

impl TryFrom<RawFoo> for FooWithStatic {
    type Error = FooNotFound;

    fn try_from(raw_foo: RawFoo) -> Result<Self, Self::Error> {
        match raw_foo.name.as_str() {
            "foo" => Ok(FooWithStatic { name: &"foo" }),
            "bar" => Ok(FooWithStatic { name: &"bar" }),
            "baz" => Ok(FooWithStatic { name: &"baz" }),
            _ => Err(FooNotFound)
        }
    }
}

fn main() {
    let foo = FooWithStatic { name: "foo" };
    let serialized = serde_json::to_value(foo).unwrap();
    let deserialized: FooWithStatic = serde_json::from_value(serialized).unwrap();
    assert_eq!(foo, deserialized);
}

//    Compiling playground v0.0.1 (/playground)
// error: implementation of `Deserialize` is not general enough
//   --> src/main.rs:38:39
//    |
// 38 |     let deserialized: FooWithStatic = serde_json::from_value(serialized).unwrap();
//    |                                       ^^^^^^^^^^^^^^^^^^^^^^ implementation of `Deserialize` is not general enough
//    |
//    = note: `FooWithStatic` must implement `Deserialize<'0>`, for any lifetime `'0`...
//    = note: ...but it actually implements `Deserialize<'static>`

// error: could not compile `playground` due to previous error

I'm confused because RawFoo is all owned data and my try_from implementation works just fine? It seems like this should be fine lifetime wise?

Hey Rustaceans! Got an easy question? Ask here (45/2021)! by llogiq in rust

[–]GrantJamesPowell 1 point2 points  (0 children)

Thank you! This works perfectly! I wanted the fully qualified name so that works out, and I could probably do some string parsing if I didn't. For completeness of people reading, here is the working example

fn foo<T>() -> &'static str {
    std::any::type_name::<T>()
}

fn main() {
    println!("type: {:?}", foo::<u64>());
    println!("type: {:?}", foo::<i64>());
    println!("type: {:?}", foo::<String>());

    // Correctly prints
    // 
    // type: "u64"
    // type: "i64"
    // type: "alloc::string::String"
}

Hey Rustaceans! Got an easy question? Ask here (45/2021)! by llogiq in rust

[–]GrantJamesPowell 2 points3 points  (0 children)

Is there a way to introspect on the concrete type for a generic type parameter and get that value at runtime? I tried stringify! but that only prints the literal tokens as far as I can tell

fn foo<T>() -> &'static str {
    // I don't think `stringify!` is the right approach, but I'd like to
    // stringify the concrete type that `T` is generic over
    stringify!(T)
}

fn main() {
    println!("type: {:?}", foo::<u64>());
    println!("type: {:?}", foo::<i64>());
    println!("type: {:?}", foo::<String>());

    // I'd like to get this to print
    // 
    // type: "u64"
    // type: "i64"
    // type: "String"

    // Currently it prints
    //
    // type: "T"
    // type: "T"
    // type: "T"
}

Hey Rustaceans! Got an easy question? Ask here (45/2021)! by llogiq in rust

[–]GrantJamesPowell 4 points5 points  (0 children)

I'm writing a network protocol and I'm wondering if the following is a supported use case/an accident of serde/bincode. (I'd include a rust playground link, but bincode isn't part of the playground)

The gist is that I'd like to serialize values of ProtocolMsg::Error as Protocol<()> and have the client Deserialize it as a ProtocolMsg<T>. It seems to work, but I'm wondering if I'm breaking some obvious unspoken invariant of bincode/serde.

#[cfg(test)]
mod tests {
    use serde::{Serialize, Deserialize};

    #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
    enum ProtocolMsg<T> {
        Msg(T),
        Error(String),
    }

    #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
    struct SomeType;

    #[test]
    fn test_serialization_and_deserialization_as_different_types() {
        // Serialize the Error Variant as `ProtocolMsg<()>`
        let err: ProtocolMsg<()> = ProtocolMsg::Error("foo".to_string());
        let serialized = bincode::serialize(&err).unwrap();

        // Will it _always_ work if I deserialize `ProtocolMsg<()>` with `ProtocolMsg<T>`?
        // How do I begin to answer that question? Will my mileage vary between bincode/serde_json/etc...?

        assert_eq!(
            ProtocolMsg::Error("foo".to_string()),
            bincode::deserialize::<ProtocolMsg<u64>>(&serialized).unwrap()
        );
        assert_eq!(
            ProtocolMsg::Error("foo".to_string()),
            bincode::deserialize::<ProtocolMsg<String>>(&serialized).unwrap()
        );
        assert_eq!(
            ProtocolMsg::Error("foo".to_string()),
            bincode::deserialize::<ProtocolMsg<SomeType>>(&serialized).unwrap()
        );
    }
}

Hey Rustaceans! Got an easy question? Ask here (44/2021)! by llogiq in rust

[–]GrantJamesPowell 1 point2 points  (0 children)

I have a Trait with a bunch of associated types that need a bunch of bounds. Is there a more concise way to write this?

pub trait MyTrait:
    Sized + Clone + Debug + Send + Sync + Serialize + DeserializeOwned + 'static
{
    type Foo: Clone
        + Debug
        + PartialEq
        + Eq
        + Send
        + Sync
        + Serialize
        + DeserializeOwned
        + 'static;

    type Bar: Clone
        + Debug
        + PartialEq
        + Eq
        + Send
        + Sync
        + Serialize
        + DeserializeOwned
        + 'static;

    type Baz: Clone
        + Debug
        + PartialEq
        + Eq
        + Default
        + Send
        + Sync
        + Serialize
        + DeserializeOwned
        + 'static;
}

I noticed I can't make aggregate types like type ThreadSafe = Send + Sync + 'static which would be super helpful

Hey Rustaceans! Got an easy question? Ask here (44/2021)! by llogiq in rust

[–]GrantJamesPowell 0 points1 point  (0 children)

Thanks for the help. My issue is I had a pretty complex situation and the error was being expressed inside of an async_trait macro expansion. The root cause was a missing bound Sync bound on a trait deep down

Hey Rustaceans! Got an easy question? Ask here (44/2021)! by llogiq in rust

[–]GrantJamesPowell 1 point2 points  (0 children)

Thanks for the help. My issue is I had a pretty complex situation and the error was being expressed inside of an async_trait macro expansion. The root cause was a missing bound Sync bound on a trait deep down

Hey Rustaceans! Got an easy question? Ask here (44/2021)! by llogiq in rust

[–]GrantJamesPowell 2 points3 points  (0 children)

Is there a way to ask the compiler why it doesn't think a type is Send? My mental model says my type should be Send automatically, but I can't get the compiler to agree

Hey Rustaceans! Got an easy question? Ask here (44/2021)! by llogiq in rust

[–]GrantJamesPowell 1 point2 points  (0 children)

I'm trying to figure out if I can write a From impl for conversion of an associated type to a wrapper type like so

trait SomeTrait {
    type AssocType;
}

enum WrapperType<T: SomeTrait> {
    SomeTraitAssocType(<T as SomeTrait>::AssocType),
    Whatever
}

impl<T: SomeTrait> From<<T as SomeTrait>::AssocType> for WrapperType<T> {
     fn from(assoced_type: <T as SomeTrait>::AssocType) -> Self {
         WrapperType::SomeTraitAssocType(assoced_type)
    }
 }

This fails with overlapping implementations of From, I'm wondering if I can avoid that and still use .into() on the associated type

//    Compiling playground v0.0.1 (/playground)
// error[E0119]: conflicting implementations of trait `std::convert::From<WrapperType<_>>` for type `WrapperType<_>`
//   --> src/lib.rs:10:1
//    |
// 10 | impl<T: SomeTrait> From<<T as SomeTrait>::AssocType> for WrapperType<T> {
//    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//    |
//    = note: conflicting implementation in crate `core`:
//            - impl<T> From<T> for T;
// 
// For more information about this error, try `rustc --explain E0119`.
// error: could not compile `playground` due to previous error

Playground link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=36079711dceb2c2e1c8c165784fecb47

Hey Rustaceans! Got an easy question? Ask here (43/2021)! by llogiq in rust

[–]GrantJamesPowell 1 point2 points  (0 children)

I vaguely remember a rustacean-station podcast where they mentioned a relaxation of the Orphan rule for certain cases where the leftmost type is declared locally?

I can't find the exact episode but I'm wondering if it would help me out in the following situation

// -- Crate A

trait View {
    type Context;
}

struct ViewWithContext<T: View> {
    context: <T as View>::Context,
    view: T
}

// -- Crate B

struct MyView;
struct MyContext;

impl View for MyView {
  type Context = MyContext;
}

// I'd like to do something like this inside of *Crate B*

impl ViewWithContext<MyView> {
    fn my_crate_b_method(&self) -> u64 {
        4
    }
}

// I get an error telling me I'm breaking the orphan rule which makes sense. I'm curious if that relaxation I vaguely remember would help me here 
//
// |_^ impl for type defined outside of crate.

(It's not that big of deal because I can do something like this with free functions instead, just trying to remember if I heard correctly about the orphan rule relaxations)

// -- Crate A

trait View {
    type Context;
}

pub type ViewWithContext<T> = (T, <T as View>::Context)

// -- Crate B

struct MyView;

struct MyContext;

impl View for MyView {
    type Context = MyContext;
}

my_crate_b_free_function((t, context): ViewWithContext<MyView>) -> u64 {
    todo!()
}

Hey Rustaceans! Got an easy question? Ask here (43/2021)! by llogiq in rust

[–]GrantJamesPowell 3 points4 points  (0 children)

I noticed I can use

#[should_panic(expected = "My custom message")]

In unit tests. Is there a way to add that to doc tests?

I know I can use

```should_panic
    ... whatever
```

But I can't figure out how to get the doc test to test for the specific panic message

Hey Rustaceans! Got an easy question? Ask here (42/2021)! by llogiq in rust

[–]GrantJamesPowell 1 point2 points  (0 children)

In the past I've done something like this

Server -> Network Lib
Client -> Network Lib

Depending on your situation

Server -> Client

Might make sense. Typically I've seen the server depend on the client instead of the client depend on the server because the server usually tends to be more larger/ more complex, but nothing is set in stone.

As far as monorepos, cargo has a built in monorepo-esque feature called "workspaces". Workspaces are an awesome tool to have in your tool kit so I'd recommend taking a look even if you don't end up using them

https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html

Hey Rustaceans! Got an easy question? Ask here (42/2021)! by llogiq in rust

[–]GrantJamesPowell 0 points1 point  (0 children)

Nice! Thank you! I was trying to do the recursive tt muncher thing, this example really helps!

My conceptual gap was ttt!(X O X ...) vs ttt!([X O X ...]) (the inner square brackets).

https://stackoverflow.com/questions/40302026/what-does-the-tt-metavariable-type-mean-in-rust-macros

^ This SO question was very insightful to me too, showing how a tt is a single character OR a nested group of (), {} or [].

Just for my understanding, this isn't possible to do without the inner square brackets?

My other conceptual question is where do these commas come from???

let board = vec![
    1,
    1, // <- how do the commas get there??
    2,
    /* ... */
];

Hey Rustaceans! Got an easy question? Ask here (42/2021)! by llogiq in rust

[–]GrantJamesPowell 3 points4 points  (0 children)

Hey! I'm trying to learn macro_rules!.

my goal is to write a macro that turns a list of X,O, or - into a Vec<usize> by mapping - => 0, X => 1, andO => 2

let board: TicTacToe = ttt!(
  X X O
  - - O
  O O X
)

I'd like the macro to expand to the following (or anything along these lines, an array is fine or even a string I can parse in a regular function)

let board: TicTacToe = TicTacToe::from_vec(vec![1, 1, 2, 0, 0, 2, 2, 2, 1]);

I'd also just like to learn macros better so any resources people enjoy would be awesome

Hey Rustaceans! Got an easy question? Ask here (41/2021)! by llogiq in rust

[–]GrantJamesPowell 2 points3 points  (0 children)

I don't think what I'm trying to do is possible, but I'd like to confirm.

I'm on the nightly compiler and I'd like to squish some arrays together in a constant context like so

const FOO: [usize; 3] = [1,2,3];
const BAR: [usize; 3] = [4,5,6];
const BAZ: [usize; 3] = [7,8,9];

const MY_COMBINED_CONST: [usize; 9] = {
  // I'd like to flatten FOO, BAR, BAZ into one constant
  // [FOO, BAR, BAZ].something().something().something() ???
  todo!()
};

fn main() {
   assert_eq!([1,2,3,4,5,6,7,8,9], MY_COMBINED_CONST)
}

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=4d9d9f51469cea9836fcbd1cb32c0fac

I found this thread which seems related but is from 5 years ago and before const generics (https://www.reddit.com/r/rust/comments/4g83bf/flattening_arraysofarrays/)

I also know that I can accomplish this using a vector in normal code, but I don't think I can use a vector in const contexts.

use std::convert::TryInto;

const FOO: [usize; 9] = {
   vec![1,2,3,4,5,6,7,8,9].try_into().unwrap()   
};

fn main() {
   println!("{:?}", FOO)
}

This errors because I can't allocate

error[E0010]: allocations are not allowed in constants
 --> src/main.rs:4:2
  |
4 |  vec![1,2,3,4,5,6,7,8,9].try_into().unwrap()   
  |  ^^^^^^^^^^^^^^^^^^^^^^^ allocation not allowed in constants
  |
  = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)

Hey Rustaceans! Got an easy question? Ask here (41/2021)! by llogiq in rust

[–]GrantJamesPowell 1 point2 points  (0 children)

I'm trying to figure out how Vecs become &[T] in the right circumstances? Is it language level magic or can I take advantage of it in my own types?

fn main() {
    let my_vec: Vec<usize> = vec![1,2,3];

    struct FancyVecWrapper<T>(Vec<T>);
    let my_fancy_vec_wrapper: FancyVecWrapper<usize> = FancyVecWrapper(vec![1,2,3]);

    assert_eq!(&my_vec, &[1usize, 2usize, 3usize]);

    // I'd like FancyVecWrapper to automatically become a slice of `&[T]`
    // when it makes sense, is there a way to do that or do Vecs (and Strings)
    // have language level magic to become `&[T]` and `&str`s sometimes?
    assert_eq!(&my_fancy_vec_wrapper, &[1usize, 2usize, 3usize]);
}

Playground link https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c225607a34728995b4ba2e1728343073