Rust의 비트 플래그
배경
Season of KDE 2022의 일부로 KConfig에 대한 Rust 바인딩 작업을 하는 동안 Rust에서
QFlags
을 표현하려고 하는 동안 몇 가지 문제를 발견했습니다.QFlags
은 여러 멤버가 동일한 값을 가질 수 있는 C++ 열거형으로 정의됩니다. 이것은 Rust 열거형에서는 불가능합니다. 이 게시물은 내가 생각해낸 다양한 구현과 그 절충안을 안내할 것입니다.
C++ 열거형
구현하려고 했던 열거형은
KConfig::OpenFlags
입니다. 열거형은 아래와 같습니다.enum OpenFlag {
IncludeGlobals = 0x01, ///< Blend kdeglobals into the config object.
CascadeConfig = 0x02, ///< Cascade to system-wide config files.
SimpleConfig = 0x00, ///< Just a single config file.
NoCascade = IncludeGlobals, ///< Include user's globals, but omit system settings.
NoGlobals = CascadeConfig, ///< Cascade to system settings, but omit user's globals.
FullConfig = IncludeGlobals | CascadeConfig, ///< Fully-fledged config, including globals and cascading to system settings
};
구현 1: Rust 모듈 사용
이 방법은 Rust 모듈과 상수의 조합을 사용합니다. 샘플 구현은 다음과 같습니다.
pub mod OpenFlags {
type E = u32;
const INCLUDE_GLOBALS: Self::E = 0x01;
const CASCADE_CONFIG: Self::E = 0x02;
const SIMPLE_CONFIG: Self::E = 0x00;
const NO_CASCASE: Self::E = Self::INCLUDE_GLOBALS;
const NO_GLOBALS: Self::E = Self::CASCADE_CONFIG;
const FULL_CONFIG: Self::E = Self::INCLUDE_GLOBALS | Self::CASCADE_CONFIG;
}
fn something(flag: OpenFlags::E) {}
장점
단점
구현 2: Impl에서 const 사용
이 메서드는 문제가 있는 멤버를
const
의 impl
로 정의합니다. 샘플 구현은 다음과 같습니다.#[repr(C)]
pub enum OpenFlags {
IncludeGlobals = 0x01,
CascadeConfig = 0x02,
SimpleConfig = 0x00,
FullConfig = 0x01 | 0x02,
}
#[allow(non_upper_case_globals)]
impl OpenFlags {
const NoCascade: Self = Self::IncludeGlobals;
const NoGlobals: Self = Self::CascadeConfig;
}
fn something(flag: OpenFlags) {}
장점
단점
구현 3: C++로 전달할 때 표준 Rust 열거형 변환
이 방법은 표준 녹 열거형을 사용합니다. 샘플 구현은 다음과 같습니다.
pub enum OpenFlags {
IncludeGlobals,
CascadeConfig,
SimpleConfig,
NoCascade,
NoGlobals,
FullConfig
}
impl OpenFlags {
type E = u32;
const INCLUDE_GLOBALS: Self::E = 0x01;
const CASCADE_CONFIG: Self::E = 0x02;
const SIMPLE_CONFIG: Self::E = 0x00;
pub fn to_cpp(&self) -> Self::E {
match self {
Self::IncludeGlobals => Self::INCLUDE_GLOBALS,
Self::CascadeConfig => Self::CASCADE_CONFIG,
Self::SimpleConfig => Self::SIMPLE_CONFIG,
Self::NoCascade => Self::INCLUDE_GLOBALS,
Self::NoGlobals => Self::CASCADE_CONFIG,
Self::FullConfig => Self::INCLUDE_GLOBALS | Self::CASCADE_CONFIG,
}
}
}
fn something(flag: OpenFlags) {
let flag = flag.to_cpp();
...
}
장점
단점
OpenFlag::IncludeGlobal | OpenFlag::CascadeConfig
불가능 구현 4: bitflags 크레이트 사용
이것이 내가 마침내 결정한 구현입니다. 구현은 다음과 같습니다.
use bitflags::bitflags
bitflags! {
/// Determines how the system-wide and user's global settings will affect the reading of the configuration.
/// This is a bitfag. Thus it is possible to pass options like `OpenFlags::INCLUDE_GLOBALS |
/// OpenFlags::CASCADE_CONFIG`
#[repr(C)]
pub struct OpenFlags: u32 {
/// Blend kdeglobals into the config object.
const INCLUDE_GLOBALS = 0x01;
/// Cascade to system-wide config files.
const CASCADE_CONFIG = 0x02;
/// Just a single config file.
const SIMPLE_CONFIG = 0x00;
/// Include user's globals, but omit system settings.
const NO_CASCADE = Self::INCLUDE_GLOBALS.bits;
/// Cascade to system settings, but omit user's globals.
const NO_GLOBALS = Self::CASCADE_CONFIG.bits;
/// Fully-fledged config, including globals and cascading to system settings.
const FULL_CONFIG = Self::INCLUDE_GLOBALS.bits | Self::CASCADE_CONFIG.bits;
}
}
fn something(flag: OpenFlags) {}
장점
단점
struct
로 표시됩니다. 문서 스크린샷
결론
나는 가까운 장래에 bitflags의 모든
QFlags
를 나타내기 위해 kconfig을 사용할 것이라고 생각합니다.
Reference
이 문제에 관하여(Rust의 비트 플래그), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/ayush1325/bitflags-in-rust-2d2p텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)