1

Background

I am writing a library, some related code are shown below:

pub struct MyStruct1;

pub struct MyStruct2;

pub enum MyEnum {
    Variant1(MyStruct1),
    Variant2(MyStruct2)
}

// out of this crate
fn foo(my_enum: Rc<RefCell<MyEnum>>) {
    match &*my_enum.borrow() {
        Variant1(my_struct1) => { /* do something */ },
        Variant2(my_struct2) => { /* do something */ }
    }
}

Target

MyEnum is always used wrapped in Rc<RefCell<MyEnum>>. So I want to hide it in a newtype struct as described in is-it-possible-to-implement-methods-on-type-aliases:

//make this only public to crate
pub(crate) enum MyEnum;

pub struct ExposedMyEnum(pub(crate) Rc<RefCell<MyEnum>>);

And I don't want others who uses my crate to know the existence of Rc<RefCell<>>.

Problem

If I use ExposedMyEnum to hide the annoying Rc<RefCell<MyEnum>>, I can't do pattern matching as foo do out of this crate.

Ungraceful solution

Change the original code to

struct MyStruct1;
struct MyStruct2;

pub struct ExposedMyStruct1(pub(crate) Rc<RefCell<MyStruct1>>);
pub struct ExposedMyStruct2(pub(crate) Rc<RefCell<MyStruct2>>);

pub enum MyEnum {
    Variant1(ExposedMyStruct1),
    Variant2(ExposedMyStruct1)
}

// out of this crate
fn foo(my_enum: &MyEnum) {
    match &my_enum {
        Variant1(my_struct1) => { /* do something */ },
        Variant2(my_struct2) => { /* do something */ }
    }
}

I need to create newtype structs for each variant, which is not graceful.

Community
  • 1
  • 1
Evian
  • 1,035
  • 1
  • 9
  • 22

1 Answers1

1

The solution is rather simple: one can refer to the members of tuple and tuple-like struct by syntax .0, .1 and so on, like so:

use std::cell::RefCell;
use std::rc::Rc;

pub struct MyStruct1;

pub struct MyStruct2;

pub(crate) enum MyEnum {
    Variant1(MyStruct1),
    Variant2(MyStruct2),
}

pub struct ExposedMyEnum(pub(crate) Rc<RefCell<MyEnum>>);

fn foo(my_enum: ExposedMyEnum) {
    match &*my_enum.0.borrow() {
        MyEnum::Variant1(my_struct1) => { /* do something */ }
        MyEnum::Variant2(my_struct2) => { /* do something */ }
    }
}
edwardw
  • 12,652
  • 3
  • 40
  • 51
  • 1
    This works, but I don't want others who uses my crate to know the existence of `Rc>`, and `foo` is an example method used by users. In your implementation, the use of `borrow` still leaks the `RefCell` thing, is there any method I can achieve my goal? – Evian Feb 09 '20 at 01:40