#converting owned values to owned enum variants

12 messages · Page 1 of 1 (latest)

crimson vine
#

i have some enum that looks like

enum E {
  T(egg),
  ...
}

and i have a value which is of type &T, which i want to change into &E::T
i can't just use E::T(value), because it's borrowed
and i can't do &E::T(value.clone()) because T doesn't implement Clone
what's the best way to go about doing this

humble willow
crimson vine
#

=/ well fuck
i need to rethink my design

humble willow
#

If you provide a bit more context to explain why you ended up in a situation where you needed that conversion, then we could probably help a bit more ;)

crimson vine
#

context stack:

  • interpreter for dynamically typed lang
  • objects represented in one big enum
  • need a method on variants to convert it into the big enum
  • all of the variants are Cloneable except for one which has a Box<FnMut(...) -> ...>
  • if i can transform &self into &Object::...(self) i could return it and avoid Cloneing it
  • this question
humble willow
#

mhh, could this conversion be changed to accept owned values and return an owned enum instead ?

crimson vine
#

yeah fair

#

converting owned values to owned enum variants

#

ish

agile hedge
#

There is an unsafe way, but it has a lot of considerations:

If you make the enum #[repr(u8)] (or any other integer repr, but not a #[repr(C, Int)]), then it has a stable layout (described here: https://rust-lang.github.io/rfcs/2195-really-tagged-unions.html). You could mimic that layout with a #[repr(C)] struct, and then you'd be allowed to transmute between them.

To clarify:

#[repr(u8)]
enum TwoCases {
    A(u8, u16),
    B(u16),
}
```Has the same layout as
```rs
union TwoCasesRepr {
    A: TwoCasesVariantA,
    B: TwoCasesVariantB,
}

#[repr(u8)]
enum TwoCasesTag { A, B }

#[repr(C)]
struct TwoCasesVariantA(TwoCasesTag, u8, u16);

#[repr(C)]
struct TwoCasesVariantB(TwoCasesTag, u16);
```As a consequence, `transmute::<TwoCasesVariantB, TwoCases>(variant_b)` is a correct operation.

As for `transmute::<&TwoCasesVariantB, &TwoCases>(&variant_b)`, that one is _also_ correct, **provided the aligment lines up**. If the enum as a higher alignment than its "variant struct", then this isn't always correct. (also, put this in a helper function. By default, `transmute` doesn't "connect" the lifetimes, it just makes the output have an unbounded one)
#

(get #dark-arts to doublecheck this, tho, if you choose to follow this idea)

crimson vine
#

the solution was to in fact
learn how the fuck rust actually works
i meant fn, not Fn
so im afraid im gonna have to pull an xkcd 979