Created
May 19, 2017 07:18
-
-
Save tmfink/c8a7f72c1dcb3f54510ee0a01b303d95 to your computer and use it in GitHub Desktop.
Stable Rust Bindgen unions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include "my_union.h" | |
void print_foo(struct Foo *foo) { | |
if (foo == NULL) { | |
printf("Got NULL pointer"); | |
return; | |
} | |
switch (foo->type) { | |
case CHAR: | |
printf("%c", foo->value.c); | |
break; | |
case INTEGER: | |
printf("%d", foo->value.i); | |
break; | |
default: | |
printf("Unexpected case"); | |
return; | |
} | |
} | |
int main() { | |
struct Foo foo1 = { | |
.type = CHAR, | |
.value = { .c = 'A' }, | |
}; | |
struct Foo foo2 = { | |
.type = INTEGER, | |
.value = { .i = 1337 }, | |
}; | |
printf("foo1 = "); | |
print_foo(&foo1); | |
printf("\n"); | |
printf("foo2 = "); | |
print_foo(&foo2); | |
printf("\n"); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
enum Foo_type { | |
CHAR, | |
INTEGER, | |
}; | |
struct Foo { | |
enum Foo_type type; | |
union { | |
char c; | |
int i; | |
} value; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//! Demonstration of using bindgen-generated union structs | |
#![allow(non_camel_case_types)] | |
use std::fmt; | |
// C header: | |
// | |
// enum Foo_type { | |
// CHAR, | |
// INTEGER, | |
// }; | |
// | |
// struct Foo { | |
// enum Foo_type type; | |
// union { | |
// char c; | |
// int i; | |
// } value; | |
// }; | |
/// Created with `bindgen --no-layout-tests --no-unstable-rust my_union.h` | |
/// (version 0.25) | |
// ******************************************************** | |
#[repr(C)] | |
pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>); | |
impl<T> __BindgenUnionField<T> { | |
#[inline] | |
pub fn new() -> Self { | |
__BindgenUnionField(::std::marker::PhantomData) | |
} | |
#[inline] | |
pub unsafe fn as_ref(&self) -> &T { | |
::std::mem::transmute(self) | |
} | |
#[inline] | |
pub unsafe fn as_mut(&mut self) -> &mut T { | |
::std::mem::transmute(self) | |
} | |
} | |
impl<T> ::std::default::Default for __BindgenUnionField<T> { | |
#[inline] | |
fn default() -> Self { | |
Self::new() | |
} | |
} | |
impl<T> ::std::clone::Clone for __BindgenUnionField<T> { | |
#[inline] | |
fn clone(&self) -> Self { | |
Self::new() | |
} | |
} | |
impl<T> ::std::marker::Copy for __BindgenUnionField<T> {} | |
impl<T> ::std::fmt::Debug for __BindgenUnionField<T> { | |
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { | |
fmt.write_str("__BindgenUnionField") | |
} | |
} | |
#[repr(u32)] | |
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | |
pub enum Foo_type { | |
CHAR = 0, | |
INTEGER = 1, | |
} | |
#[repr(C)] | |
#[derive(Debug, Copy)] | |
pub struct Foo { | |
pub type_: Foo_type, | |
pub value: Foo__bindgen_ty_1, | |
} | |
#[repr(C)] | |
#[derive(Debug, Copy)] | |
pub struct Foo__bindgen_ty_1 { | |
pub c: __BindgenUnionField<::std::os::raw::c_char>, | |
pub i: __BindgenUnionField<::std::os::raw::c_int>, | |
pub bindgen_union_field: u32, | |
} | |
impl Clone for Foo__bindgen_ty_1 { | |
fn clone(&self) -> Self { | |
*self | |
} | |
} | |
impl Clone for Foo { | |
fn clone(&self) -> Self { | |
*self | |
} | |
} | |
// ******************************************************** | |
/// Helper macro to instantiate bindgen union | |
macro_rules! new_bindgen_union { | |
($union_type:ty, $variant:ident, $value:expr) => {{ | |
let mut temp: $union_type = unsafe { ::std::mem::uninitialized() }; | |
*unsafe { temp.$variant.as_mut() } = $value; | |
temp | |
}}; | |
} | |
impl fmt::Display for Foo { | |
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
match self.type_ { | |
Foo_type::CHAR => { | |
let value = *unsafe { self.value.c.as_ref() } as u8 as char; | |
write!(f, "{:?}", value) | |
} | |
Foo_type::INTEGER => { | |
let value = *unsafe { self.value.i.as_ref() }; | |
write!(f, "{}", value) | |
} | |
} | |
} | |
} | |
fn main() { | |
// Create struct with union field "manually" | |
let mut foo1_value: Foo__bindgen_ty_1 = unsafe { ::std::mem::uninitialized() }; | |
*unsafe { foo1_value.c.as_mut() } = 'A' as ::std::os::raw::c_char; | |
let foo1 = Foo { | |
type_: Foo_type::CHAR, | |
value: foo1_value, | |
}; | |
// Create union with `new_bindgen_union` convenience macro | |
let foo2 = Foo { | |
type_: Foo_type::INTEGER, | |
value: new_bindgen_union!(Foo__bindgen_ty_1, i, 1337), | |
}; | |
println!("foo1 = {}", foo1); | |
println!("foo2 = {}", foo2); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment