Скрыть закрытые поля библиотеки Rust при генерации ее заголовка C

Я делаю библиотеку Rust, содержащую следующий код:

pub mod my_module{

    use std::os::raw::{c_int, c_double};
    use std::collections::HashMap;

    struct MyPrivateClass {
        my_parameter:c_int
    }

    (...)

    #[repr(C)]
    pub struct MyPublicClass {
        my_private_parameter:HashMap<String,MyPrivateClass>,
        pub my_public_parameter:c_int,
        pub my_other_public_parameter:c_double
    }

    (...)

}

Я хочу использовать эту библиотеку из Objective-C. Итак, я использую cbindgen для создания заголовка C. В моем проекте Objective-C мне нужен только доступ к общедоступным полям MyPublicClass. Но сгенерированный заголовок C содержит все поля моих публичных структур, включая частное поле.

Вот как выглядит сгенерированный заголовок C:

#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

typedef struct HashMap_String__MyPrivateClass HashMap_String__MyPrivateClass;

typedef struct {
  HashMap_String__MyPrivateClass my_private_parameter;
  int my_public_parameter;
  double my_other_public_parameter;
} MyPublicClass;

В этом конкретном случае тип HashMap не имеет прямого эквивалента C, поэтому я не могу использовать этот заголовок C.

Мне нужно использовать этот HashMap только внутри моей библиотеки Rust. Мне не нужно использовать его из Objective-C.

Как я могу создать заголовок C, который не раскрывает его, ничего не нарушая?

1 ответ

В итоге я последовал за ответом Маккартона и избавился от необходимости предоставлять MyPublicClass для моего заголовка C.

Как следствие, я полагаюсь на функции для доступа к параметрам, вместо того, чтобы обращаться к ним напрямую как к параметрам экземпляра. У этого есть недостаток, заключающийся в невозможности проверки значений полей MyPublicClass из отладчика при запуске моего проекта Objective-C из Xcode, но, по крайней мере, он компилируется и работает должным образом.

Мой код на Rust:

// This struct is no longer exposed to C:
pub struct MyPublicClass {
    my_private_parameter:HashMap<String,MyPrivateClass>,
    pub my_public_parameter:c_int,
    pub my_other_public_parameter:c_double
}


impl MyPublicClass {
    pub fn new() -> Self {
        (…)
        MyPublicClass {
            my_private_parameter: … ,
            my_public_parameter: … ,
            my_other_public_parameter: … ,
        }
    }

    // Necessary to access my_public_parameter outside of Rust:
    pub fn get_my_public_parameter_value(&self) -> c_int {
        return self.my_public_parameter;
    }
}

// Exposed to C:
#[no_mangle]
pub unsafe extern fn my_public_class_new() -> *mut MyPublicClass {
    Box::into_raw(Box::new(MyPublicClass::new()))
}

// Exposed to C and necessary to access my_public_parameter outside of Rust:
#[no_mangle]
pub unsafe extern fn my_public_class_get_my_public_parameter_value(ptr: *mut MyPublicClass) -> c_int {
    let mpc = unsafe {
        assert!(!ptr.is_null());
        &mut *ptr
    };
    mpc.get_my_public_parameter_value()
}

Заголовок C:

#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

typedef struct MyPublicClass MyPublicClass;
MyPublicClass *my_public_class_new();
int my_public_class_get_my_public_parameter_value(MyPublicClass *ptr);
Другие вопросы по тегам