Skip to content

Instantly share code, notes, and snippets.

@lu-zero
Forked from rust-play/playground.rs
Created September 29, 2018 22:08
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 lu-zero/8349e47b04b5af26a1d61d2455db541e to your computer and use it in GitHub Desktop.
Save lu-zero/8349e47b04b5af26a1d61d2455db541e to your computer and use it in GitHub Desktop.
Code shared from the Rust Playground
#![feature(ptr_offset_from)]
use std::marker::PhantomData;
#[derive(Debug, Clone, Copy)]
struct PlaneInfo {
stride: usize,
w: usize,
h: usize,
}
#[derive(Debug, Clone)]
struct Plane {
data: Vec<u8>,
info: PlaneInfo,
}
use std::fmt;
impl fmt::Display for Plane {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let data = self
.data
.chunks(self.info.stride)
.take(self.info.h)
.map(|c| &c[..self.info.w]);
f.debug_list().entries(data).finish()
}
}
#[derive(Debug, Clone, Copy)]
struct TileInfo {
w: usize,
h: usize,
}
impl Plane {
fn new(info: PlaneInfo) -> Self {
Plane {
data: vec![128u8; (info.h + 1) * info.stride],
info,
}
}
fn tile_iter_mut<'a>(&'a mut self, tile_info: TileInfo) -> TileIterMut<'a> {
TileIterMut {
start: self.data.as_mut_ptr(),
end: unsafe { self.data.as_ptr().offset(self.data.len() as isize) },
plane_info: self.info,
tile_info,
w_off: 0,
h_off: 0,
f: PhantomData,
}
}
}
#[derive(Debug, Clone, Copy)]
struct TileIterMut<'a> {
start: *mut u8,
end: *const u8,
plane_info: PlaneInfo,
tile_info: TileInfo,
w_off: usize,
h_off: usize,
f: PhantomData<&'a mut Plane>,
}
impl<'a> Iterator for TileIterMut<'a> {
type Item = TileMut<'a>;
fn next(&mut self) -> Option<TileMut<'a>> {
let y = self.h_off;
let x = self.w_off;
let stride = self.plane_info.stride;
let base = (y * stride + x) as isize;
let start = unsafe { self.start.offset(base) };
let tile_size = (self.tile_info.h * stride + self.tile_info.w) as isize;
let end = unsafe { start.offset(tile_size) } as *const u8;
if end > self.end {
println!("exit at {}x{} {}", self.h_off, self.w_off, unsafe {
end.offset_from(self.end)
});
None
} else {
let next_w_off = self.w_off + self.tile_info.w;
if next_w_off >= self.plane_info.w {
self.h_off += self.tile_info.h;
self.w_off = 0;
} else {
self.w_off = next_w_off;
}
println!("off {}x{} {}", self.h_off, self.w_off, unsafe {
end.offset_from(start as *const u8)
});
Some(TileMut {
start,
end,
tile_info: self.tile_info,
stride: self.plane_info.stride,
f: PhantomData,
})
}
}
}
#[derive(Debug, Clone, Copy)]
struct TileMut<'a> {
start: *mut u8,
end: *const u8,
tile_info: TileInfo,
stride: usize,
f: PhantomData<&'a mut TileIterMut<'a>>,
}
use std::ops::Index;
use std::ops::IndexMut;
impl<'a> Index<usize> for TileMut<'a> {
type Output = u8;
fn index<'b>(&'b self, index: usize) -> &'b u8 {
let h = index / self.tile_info.w;
let w = index % self.tile_info.w;
let pos = unsafe { self.start.offset((h * self.stride + w) as isize) };
if pos >= self.end as *mut u8 {
panic!("Index out of range");
} else {
unsafe { pos.as_ref().unwrap() }
}
}
}
impl<'a> IndexMut<usize> for TileMut<'a> {
fn index_mut<'b>(&'b mut self, index: usize) -> &'b mut u8 {
let h = index / self.tile_info.w;
let w = index % self.tile_info.w;
let pos = unsafe { self.start.offset((h * self.stride + w) as isize) };
if pos >= self.end as *mut u8 {
panic!("Index out of range");
} else {
unsafe { pos.as_mut().unwrap() }
}
}
}
#[derive(Debug, Clone, Copy)]
struct LineIterMut {
ptr: *mut u8,
tile_info: TileInfo,
h_off: usize,
}
fn main() {
let mut plane = Plane::new(PlaneInfo {
stride: 128,
w: 64,
h: 64,
});
let tile_info = TileInfo { w: 16, h: 16 };
plane
.tile_iter_mut(tile_info)
.enumerate()
.for_each(|(i, mut t)| {
println!("{} {:?}", i, t);
t[0] = i as u8;
});
println!("{:#}", plane);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment