Handling Attributes

You sometimes need to deal with attributes like names and class. Savvy provides the following methods for getting and setting the value of the attribute.

Getter methodSetter methodType
namesget_names()set_names()Vec<&str>
classget_class()set_class()Vec<&str>
dimget_dim()set_dim()&[i32]
arbitraryget_attrib()set_attrib()Sexp

The getter methods return Option<T> because the object doesn't always have the attribute. You can match the result like this:

/// @export
#[savvy]
fn get_class_int(x: IntegerSexp) -> savvy::Result<savvy::Sexp> {
    match x.get_class() {
        Some(class) => class.try_into(),
        None => ().try_into(),
    }
}

The setter methods are available only for owned SEXPs. The return type is savvy::Result<()> becuase the conversion from a Rust type to SEXP is fallible.

/// @export
#[savvy]
fn set_class_int() -> savvy::Result<savvy::Sexp> {
    let mut x = OwnedIntegerSexp::new(1)?;

    x.set_class(&["foo", "bar"])?;

    x.into()
}

For attributes other than names, class, dim, you can use get_attrib() and set_attrib(). Since an attribute can store arbitrary values, the type is Sexp. In order to extract the underlying value, you can use .into_typed() and match.

/// @export
#[savvy]
fn print_attr_values_if_int(attr: &str, value: savvy::Sexp) -> savvy::Result<()>  {
    let attr_value = value.get_attrib(attr)?;
    match attr_value.into_typed() {
        TypedSexp::Integer(i) => r_println!("int {:?}", i.as_slice()]),
        _ => r_println("not int")
    }

    Ok(())
}

In order to set values, you can use .into() to convert from the owned SEXP to a savvy::Sexp.

/// @export
#[savvy]
fn set_attr_int(attr: &str) -> savvy::Result<savvy::Sexp> {
    let s: &[i32] = &[1, 2, 3];
    let attr_value: OwnedIntegerSexp = s.try_into()?;
    let mut out = OwnedIntegerSexp::new(1)?;

    out.set_attrib(attr, attr_value.into())?;

    out.into()
}