For context: I am trying to write a Rust wrapper over a C library.

Like many C libraries, most of its functions return an int. Positive return values are meaningful (provides information) and negative values are error codes.

To give an example, think of something like int get_items_from_record(const struct record *rec, struct item *items). A positive value indicates how many items were returned. -1 could mean ErrorA, -2 ErrorB, and so on.

Since this is Rust, I want to represent this kind of integer as Result<T, E>, e.g.:

enum LibError {
    A = -1,
    B = -2,
    // ....
}

// LibResult is ideally just represented as an integer.
type LibResult = Result<NonNegativeInteger, LibError>;

// Then I can pass LibResult values back to the C code as i32 trivially.

Is there a way/crate to do this?

  • RunAwayFrog@sh.itjust.works
    link
    fedilink
    English
    arrow-up
    4
    arrow-down
    1
    ·
    edit-2
    11 months ago

    Discriminant is irrelevant and you’re not supposed to fuck with it.

    And there is zero reason to use unsafe/transmute for this.

    pub enum LibErr {
        ErrX,
        ErrY,
        ErrZ,
        Unknown(i32),
    }
    
    struct RetVal(i32);
    
    impl From<RetVal> for Result<i32, LibErr> {
        fn from(RetVal(ret_val): RetVal) -> Self {
            if ret_val < 0 {
                match ret_val {
                    -1 => Err(LibErr::ErrX),
                    -2 => Err(LibErr::ErrY),
                    -3 => Err(LibErr::ErrZ),
                    unknown => Err(LibErr::Unknown(unknown)),
                }
            } else { Ok(ret_val) }
        }
    }
    
    // RetVal(call_function()).into()
    
    • donnachaidh@lemmy.dcmrobertson.com
      link
      fedilink
      arrow-up
      3
      ·
      11 months ago

      And just to explicitly point out, your code’s also better because of the use of the standard traits. It took me a while to get into the habit, but using what’s already there is always a good idea.

    • Aloso@programming.dev
      link
      fedilink
      arrow-up
      2
      ·
      11 months ago

      Discriminant is irrelevant and you’re not supposed to fuck with it

      It matters because the conversion between i32 and the Result is only “free” if they have the same layout (which they do not, because of the discriminant). So a more costly conversion method is required.

      And there is zero reason to use unsafe/transmute for this.

      You are right, because the compiler is able to optimize your code quite well. However, if that optimization were to break at some point (as there is no guarantee that an optimization will continue to work in the future), it would become less efficient.

      • donnachaidh@lemmy.dcmrobertson.com
        link
        fedilink
        arrow-up
        5
        ·
        11 months ago

        That seems like strong premature optimisation. Perhaps worth a note, but I’d presume the majority of people the majority of the time wouldn’t need to worry about that.

        • Barbacamanitu@lemmy.world
          link
          fedilink
          arrow-up
          2
          arrow-down
          1
          ·
          11 months ago

          For real. Unless he’s converting between results and ints millions of times a second, I think he’s going to be just fine using the idiomatic solution. That transmute shit I’d wack lol

      • Barbacamanitu@lemmy.world
        link
        fedilink
        arrow-up
        1
        arrow-down
        1
        ·
        11 months ago

        So what! Who cares if it’s free? Write first, profile and optimize later. Not everyone cares about whether the conversion is free. Simply matching and converting to the right integer is fast enough.

        • orangeboats@lemmy.worldOP
          link
          fedilink
          arrow-up
          1
          ·
          edit-2
          11 months ago

          The reason I asked the question, was that I wanted to keep an int an int throughout the program.

          It’s not for performance reasons, it’s just that I feel like there is a certain elegance in keeping things type safe entirely “for free” much like how Option&lt;&amp;T> is actually just a regular T*, even if it could be pointless in the big picture.