Skip to content

Instantly share code, notes, and snippets.

@tmfink
Created May 19, 2017 07:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tmfink/c8a7f72c1dcb3f54510ee0a01b303d95 to your computer and use it in GitHub Desktop.
Save tmfink/c8a7f72c1dcb3f54510ee0a01b303d95 to your computer and use it in GitHub Desktop.
Stable Rust Bindgen unions
#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");
}
enum Foo_type {
CHAR,
INTEGER,
};
struct Foo {
enum Foo_type type;
union {
char c;
int i;
} value;
};
//! 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