yutannihilation / savvy

A simple R extension interface using Rust
https://yutannihilation.github.io/savvy/guide/
MIT License
63 stars 3 forks source link

Support Enum #152

Closed yutannihilation closed 5 months ago

yutannihilation commented 5 months ago

Close #149

Orig:

#[savvy]
enum Foo {
    A,
    B,
}

Expanded:

pub enum Foo {
    A = 0,
    B = 1,
}

impl TryFrom<Foo> for savvy::Sexp {
    type Error = savvy::Error;
    fn try_from(value: Foo) -> savvy::Result<Self> {
        (value as i32).try_into()
    }
}

impl TryFrom<savvy::Sexp> for Foo {
    type Error = savvy::Error;
    fn try_from(value: savvy::Sexp) -> savvy::Result<Self> {
        let i = <i32>::try_from(value)?;
        match i {
            0 => Ok(Foo::A),
            1 => Ok(Foo::B),
            _ => Err("Unexpected enum variant".into()),
        }
    }
}

C:

(No C code)

R:

.savvy_wrap_Foo <- function(ptr) {
  e <- new.env(parent = emptyenv())
  e$.ptr <- ptr

  class(e) <- "Foo"
  e
}

Foo <- new.env(parent = emptyenv())
Foo$A <- .savvy_wrap_Foo(0L)
Foo$B <- .savvy_wrap_Foo(1L)
yutannihilation commented 5 months ago

Note to future self:

I'm giving up this approach of treating an enum as integer. It works perfectly with the case of T, but when it's &T or &mut T, it's complicated and it seems it's hard to handle enum and struct transparently.