Skip to content

Instantly share code, notes, and snippets.

@bnoordhuis
Created January 26, 2014 21:41
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 bnoordhuis/8639829 to your computer and use it in GitHub Desktop.
Save bnoordhuis/8639829 to your computer and use it in GitHub Desktop.
container_of() in Rust. Look up address of embedding struct.
// Copyright (c) 2014, Ben Noordhuis <info@bnoordhuis.nl>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#[feature(macro_rules)];
macro_rules! container_of(
($ptr:expr, $kind: ty, $field: ident) => (
unsafe {
let inner = std::ptr::to_unsafe_ptr($ptr);
let outer = std::ptr::to_unsafe_ptr(&(*(0 as *$kind)).$field);
&*((inner as uint - outer as uint) as *$kind)
}
);
)
macro_rules! container_of_mut(
($ptr:expr, $kind: ty, $field: ident) => (
unsafe {
let inner = std::ptr::to_unsafe_ptr($ptr);
let outer = std::ptr::to_unsafe_ptr(&(*(0 as *$kind)).$field);
&mut *((inner as uint - outer as uint) as *mut $kind)
}
);
)
#[test]
fn test_container_of() {
struct Inner;
struct Outer {
value: int,
inner: Inner,
}
fn check(inner: &Inner) {
let outer = container_of!(inner, Outer, inner);
assert_eq!(outer.value, 42);
}
let outer = Outer { value: 42, inner: Inner };
check(&outer.inner);
}
#[test]
fn test_container_of_mut() {
struct Inner;
struct Outer {
value: int,
inner: Inner,
}
fn mutate(inner: &Inner) {
let outer = container_of_mut!(inner, Outer, inner);
outer.value *= outer.value;
}
let outer = Outer { value: 42, inner: Inner };
mutate(&outer.inner);
assert_eq!(outer.value, 42 * 42);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment