How to save a PNG image in Rust? - image

Given a vector of u8 bytes (4 bytes per pixel - RGBA), how can this be saved to a PNG file?

You could use the image crate in the Piston repository to save the raw buffer to disk.
The example at the bottom of the page shows you how to do this..:
extern crate image;
fn main() {
let buffer: &[u8] = ...; // Generate the image data
// Save the buffer as "image.png"
image::save_buffer(&Path::new("image.png"), buffer, 800, 600, image::RGBA(8))
}

This is a self contained, pure Rust implementation of a PNG image writing function.
It's based on my Python answer here.
Notes:
Since Rust doesn't expose zlib, this is quite a bit larger than the original Python code.
This avoids using zlib by writing an uncompressed image.
crc32 and adler32 checksum implementations are included as modules.
The key function to check is write, which takes any writable type (typically a file).
Example:
mod crc32 {
// https://github.com/ledbettj/crc32/blob/master/rust/src/crc32.rs
pub struct Crc32 {
table: [u32; 256],
value: u32,
}
const CRC32_INITIAL: u32 = 0xedb88320;
impl Crc32 {
pub fn new() -> Crc32 {
let mut c = Crc32 {
table: [0; 256],
value: 0xffffffff,
};
for i in 0..256 {
let mut v = i as u32;
for _ in 0..8 {
v = if v & 1 != 0 {
CRC32_INITIAL ^ (v >> 1)
} else {
v >> 1
}
}
c.table[i] = v;
}
return c;
}
pub fn start(&mut self) {
self.value = 0xffffffff;
}
pub fn update(&mut self, buf: &[u8]) {
for &i in buf {
self.value = self.table[((self.value ^ (i as u32)) & 0xff) as usize] ^
(self.value >> 8);
}
}
pub fn finalize(&mut self) -> u32 {
self.value ^ 0xffffffff_u32
}
#[allow(dead_code)]
pub fn crc(&mut self, buf: &[u8]) -> u32 {
self.start();
self.update(buf);
self.finalize()
}
}
}
mod adler32 {
// https://en.wikipedia.org/wiki/Adler-32
pub struct Adler32 {
a: u32,
b: u32,
}
const MOD_ADLER: u32 = 65521;
impl Adler32 {
pub fn new() -> Adler32 {
Adler32 { a: 1, b: 0 }
}
pub fn start(&mut self) {
self.a = 1;
self.b = 0;
}
pub fn update(&mut self, buf: &[u8]) {
for &i in buf {
self.a = (self.a + i as u32) % MOD_ADLER;
self.b = (self.a + self.b) % MOD_ADLER;
}
}
pub fn finalize(&self) -> u32 {
return (self.b << 16) | self.a;
}
#[allow(dead_code)]
pub fn crc(&mut self, buf: &[u8]) -> u32 {
self.start();
self.update(buf);
self.finalize()
}
}
}
// big endian
#[inline]
fn u32_to_u8_be(v: u32) -> [u8; 4] {
[(v >> 24) as u8, (v >> 16) as u8, (v >> 8) as u8, v as u8]
}
mod fake_zlib {
use super::adler32;
use super::u32_to_u8_be;
// Use 'none' compression
pub fn compress(data: &[u8]) -> Vec<u8> {
const CHUNK_SIZE: usize = 65530;
let final_len =
// header
2 +
// every chunk adds 5 bytes [1:type, 4:size].
(5 * {
let n = data.len() / CHUNK_SIZE;
// include an extra chunk when we don't fit exactly into CHUNK_SIZE
(n + {if data.len() == n * CHUNK_SIZE && data.len() != 0 { 0 } else { 1 }})
}) +
// data
data.len() +
// crc
4
;
let mut raw_data = Vec::with_capacity(final_len);
// header
raw_data.extend(&[120, 1]);
let mut pos_curr = 0_usize;
let mut crc = adler32::Adler32::new();
loop {
let pos_next = ::std::cmp::min(data.len(), pos_curr + CHUNK_SIZE);
let chunk_len = (pos_next - pos_curr) as u32;
let is_last = pos_next == data.len();
raw_data.extend(&[
// type
if is_last { 1 } else { 0 },
// size
(chunk_len & 0xff) as u8,
((chunk_len >> 8) & 0xff) as u8,
(0xff - (chunk_len & 0xff)) as u8,
(0xff - ((chunk_len >> 8) & 0xff)) as u8,
]);
raw_data.extend(&data[pos_curr..pos_next]);
crc.update(&data[pos_curr..pos_next]);
if is_last {
break;
}
pos_curr = pos_next;
}
raw_data.extend(&u32_to_u8_be(crc.finalize()));
assert_eq!(final_len, raw_data.len());
return raw_data;
}
}
///
/// Write RGBA pixels to uncompressed PNG.
///
pub fn write<W: ::std::io::Write>(
file: &mut W,
image: &[u8],
w: u32,
h: u32,
) -> Result<(), ::std::io::Error> {
assert!(w as usize * h as usize * 4 == image.len());
fn png_pack<W: ::std::io::Write>(
file: &mut W,
png_tag: &[u8; 4],
data: &[u8],
) -> Result<(), ::std::io::Error> {
file.write(&u32_to_u8_be(data.len() as u32))?;
file.write(png_tag)?;
file.write(data)?;
{
let mut crc = crc32::Crc32::new();
crc.start();
crc.update(png_tag);
crc.update(data);
file.write(&u32_to_u8_be(crc.finalize()))?;
}
Ok(())
}
file.write(b"\x89PNG\r\n\x1a\n")?;
{
let wb = u32_to_u8_be(w);
let hb = u32_to_u8_be(h);
let data = [wb[0], wb[1], wb[2], wb[3],
hb[0], hb[1], hb[2], hb[3],
8, 6, 0, 0, 0];
png_pack(file, b"IHDR", &data)?;
}
{
let width_byte_4 = w * 4;
let final_len = (width_byte_4 + 1) * h;
let mut raw_data = Vec::with_capacity(final_len as usize);
let mut span: u32 = (h - 1) * width_byte_4;
loop {
raw_data.push(0);
raw_data.extend(&image[(span as usize)..(span + width_byte_4) as usize]);
if span == 0 {
break;
}
span -= width_byte_4;
}
assert!(final_len == (raw_data.len() as u32));
png_pack(file, b"IDAT", &fake_zlib::compress(&raw_data))?;
}
png_pack(file, b"IEND", &[])?;
Ok(())
}
fn main() {
let mut f = std::fs::File::create("test.png").unwrap();
// image from bottom to top 3x2
let image_width = 3;
let image_height = 2;
let image = vec!(
// R G B A
0xff, 0x00, 0x00, 0xff,
0x00, 0xff, 0x00, 0xff,
0x00, 0x00, 0xff, 0xff,
0x80, 0x00, 0x00, 0xff,
0x00, 0x80, 0x00, 0xff,
0x00, 0x00, 0x80, 0xff,
);
match write(&mut f, &image, image_width, image_height) {
Ok(_) => println!("Written image!"),
Err(e) => println!("Error {:?}", e),
}
}
This has since been made into the png_encode_mini crate, which is basically the same as this snippet.

Related

Building clean and flexible binary trees in Rust

I'm using binary trees to create a simple computation graph. I understand that linked lists are a pain in Rust, but it's a very convenient data structure for what I'm doing. I tried using Box and Rc<RefCell> for the children nodes, but it didn't work out how I wanted, so I used unsafe:
use std::ops::{Add, Mul};
#[derive(Debug, Copy, Clone)]
struct MyStruct {
value: i32,
lchild: Option<*mut MyStruct>,
rchild: Option<*mut MyStruct>,
}
impl MyStruct {
unsafe fn print_tree(&mut self, set_to_zero: bool) {
if set_to_zero {
self.value = 0;
}
println!("{:?}", self);
let mut nodes = vec![self.lchild, self.rchild];
while nodes.len() > 0 {
let child;
match nodes.pop() {
Some(popped_child) => child = popped_child.unwrap(),
None => continue,
}
if set_to_zero {
(*child).value = 0;
}
println!("{:?}", *child);
if !(*child).lchild.is_none() {
nodes.push((*child).lchild);
}
if !(*child).rchild.is_none() {
nodes.push((*child).rchild);
}
}
println!("");
}
}
impl Add for MyStruct {
type Output = Self;
fn add(self, other: Self) -> MyStruct {
MyStruct{
value: self.value + other.value,
lchild: Some(&self as *const _ as *mut _),
rchild: Some(&other as *const _ as *mut _),
}
}
}
impl Mul for MyStruct {
type Output = Self;
fn mul(self, other: Self) -> Self {
MyStruct{
value: self.value * other.value,
lchild: Some(&self as *const _ as *mut _),
rchild: Some(&other as *const _ as *mut _),
}
}
}
fn main() {
let mut tree: MyStruct;
{
let a = MyStruct{ value: 10, lchild: None, rchild: None };
let b = MyStruct{ value: 20, lchild: None, rchild: None };
let c = a + b;
println!("c.value: {}", c.value); // 30
let mut d = a + b;
println!("d.value: {}", d.value); // 30
d.value = 40;
println!("d.value: {}", d.value); // 40
let mut e = c * d;
println!("e.value: {}", e.value); // 1200
unsafe {
e.print_tree(false); // correct values
e.print_tree(true); // all zeros
e.print_tree(false); // all zeros, everything is set correctly
}
tree = e;
}
unsafe { tree.print_tree(false); } // same here, only zeros
}
Link to the playground
I honestly don't mind that much using unsafe, but is there a safe way doing it? How bad is the use of unsafe here?
You can just box both of the children, since you have a unidirectional tree:
use std::ops::{Add, Mul};
use std::fmt;
#[derive(Clone)]
struct MyStruct {
value: i32,
lchild: Option<Box<MyStruct>>,
rchild: Option<Box<MyStruct>>,
}
impl fmt::Debug for MyStruct {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.debug_struct("MyStruct")
.field("value", &self.value)
.field("lchild", &self.lchild.as_deref())
.field("rchild", &self.rchild.as_deref())
.finish()
}
}
impl MyStruct {
fn print_tree(&mut self, set_to_zero: bool) {
if set_to_zero {
self.value = 0;
}
println!("MyStruct {{ value: {:?}, lchild: {:?}, rchild: {:?} }}", self.value, &self.lchild as *const _, &self.rchild as *const _);
if let Some(child) = &mut self.lchild {
child.print_tree(set_to_zero);
}
if let Some(child) = &mut self.rchild {
child.print_tree(set_to_zero);
}
}
}
impl Add for MyStruct {
type Output = Self;
fn add(self, other: Self) -> MyStruct {
MyStruct {
value: self.value + other.value,
lchild: Some(Box::new(self)),
rchild: Some(Box::new(other)),
}
}
}
impl Mul for MyStruct {
type Output = Self;
fn mul(self, other: Self) -> Self {
MyStruct {
value: self.value * other.value,
lchild: Some(Box::new(self)),
rchild: Some(Box::new(other)),
}
}
}
fn main() {
let tree = {
let a = MyStruct {
value: 10,
lchild: None,
rchild: None,
};
let b = MyStruct {
value: 20,
lchild: None,
rchild: None,
};
let c = a.clone() + b.clone();
println!("c.value: {}", c.value); // 30
let mut d = a.clone() + b.clone();
println!("d.value: {}", d.value); // 30
d.value = 40;
println!("d.value: {}", d.value); // 40
let mut e = c * d;
println!("e.value: {}", e.value); // 1200
println!("");
e.print_tree(false); // correct values
println!("");
e.print_tree(true); // all zeros
println!("");
e.print_tree(false); // all zeros, everything is set correctly
println!("");
e
};
dbg!(tree);
}
I implemented Debug manually and reimplemented print_tree recursively. I don't know if there is a way to implement print_tree as mutable like that without recursion, but it's certainly possible if you take &self instead (removing the set_to_zero stuff).
playground
Edit: Turns out it is possible to mutably iterate over the tree values without recursion. The following code is derived from the playground in this comment by #Shepmaster.
impl MyStruct {
fn zero_tree(&mut self) {
let mut node_stack = vec![self];
let mut value_stack = vec![];
// collect mutable references to each value
while let Some(MyStruct { value, lchild, rchild }) = node_stack.pop() {
value_stack.push(value);
if let Some(child) = lchild {
node_stack.push(child);
}
if let Some(child) = rchild {
node_stack.push(child);
}
}
// iterate over mutable references to values
for value in value_stack {
*value = 0;
}
}
}

Why does my program print a UTF-8 BOM on Windows?

I have the following program that works fine on Linux:
Cargo.toml
[package]
name = "ansi-color-codec"
authors = ["Richard Neumann <mail#richard-neumann.de>"]
description = "Encode bytes as ANSI background colors"
license-file = "LICENSE"
homepage = "https://github.com/conqp/ansi-color-codec/"
repository = "https://github.com/conqp/ansi-color-codec/"
readme = "README.md"
documentation = "https://docs.rs/ansi-color-codec"
keywords = [ "ANSI", "color", "encoding"]
categories = ["command-line-utilities", "encoding"]
version = "0.3.8"
edition = "2021"
exclude = [
".gitignore",
"input.txt",
]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
clap = { version = "4.0.23", features = ["derive"] }
ctrlc = "3.2.3"
[profile.release]
strip = true
lto = true
codegen-units = 1
panic = "abort"use std::iter::FlatMap;
src/lib.rs
const MASK_LOW: u8 = 0b00001111;
const MASK_HIGH: u8 = 0b11110000;
const MASK_BITS: u8 = 4;
const MASK_TRIPLET: u8 = MASK_LOW >> 1;
const COLOR_OFFSET_LOW: u8 = 40;
const COLOR_OFFSET_HIGH: u8 = 100;
const COLOR_CODE_LOW_MAX: u8 = MASK_TRIPLET;
const COLOR_CODE_MAX: u8 = MASK_LOW;
const COLOR_CODE_HIGH_BIT: u8 = 0b1000;
const MAX_DIGITS: u8 = 3;
const CODE_START: u8 = 0x1b;
const NUMBER_PREFIX: char = '[';
const NUMBER_SUFFIX: char = 'm';
const UNEXPECTED_TERMINATION_MSG: &str = "Byte stream terminated unexpectedly";
type ColorCodes<T> = FlatMap<T, [ColorCode; 2], fn(u8) -> [ColorCode; 2]>;
pub trait ColorCodec<T>
where
T: Iterator<Item = u8>,
{
fn ansi_color_encode(self) -> ColorCodes<T>;
fn ansi_color_decode(self) -> ColorCodesToBytes<ColorCodesFromBytes<T>>;
}
impl<T> ColorCodec<T> for T
where
T: Iterator<Item = u8>,
{
fn ansi_color_encode(self) -> ColorCodes<T> {
self.flat_map(|byte| byte.to_color_codes())
}
fn ansi_color_decode(self) -> ColorCodesToBytes<ColorCodesFromBytes<T>> {
ColorCodesToBytes::from(ColorCodesFromBytes::from(self))
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct ColorCode {
number: u8,
}
impl ColorCode {
pub fn new(number: u8) -> Result<Self, String> {
if (0..=COLOR_OFFSET_LOW + COLOR_CODE_LOW_MAX).contains(&number)
|| (COLOR_OFFSET_HIGH..=COLOR_OFFSET_HIGH + COLOR_CODE_LOW_MAX).contains(&number)
{
Ok(Self { number })
} else {
Err(format!("Invalid color code: {}", number))
}
}
pub fn normalized(&self) -> u8 {
if self.number < COLOR_OFFSET_HIGH {
self.number - COLOR_OFFSET_LOW
} else {
self.number - COLOR_OFFSET_HIGH + COLOR_CODE_HIGH_BIT
}
}
}
impl TryFrom<u8> for ColorCode {
type Error = String;
fn try_from(value: u8) -> Result<Self, Self::Error> {
if value <= COLOR_CODE_LOW_MAX {
Self::new(value + COLOR_OFFSET_LOW)
} else if value <= COLOR_CODE_MAX {
Self::new((value & MASK_TRIPLET) + COLOR_OFFSET_HIGH)
} else {
Err(format!("Value out of bounds for color code: {}", value))
}
}
}
impl ToString for ColorCode {
fn to_string(&self) -> String {
format!("\x1b[{}m ", self.number)
}
}
trait ColorEncodable {
fn to_color_codes(&self) -> [ColorCode; 2];
fn from_color_codes(color_codes: [ColorCode; 2]) -> Self;
}
impl ColorEncodable for u8 {
fn to_color_codes(&self) -> [ColorCode; 2] {
[
ColorCode::try_from((self & MASK_HIGH) >> MASK_BITS).unwrap(),
ColorCode::try_from(self & MASK_LOW).unwrap(),
]
}
fn from_color_codes(color_codes: [ColorCode; 2]) -> Self {
(color_codes[0].normalized() << MASK_BITS) + color_codes[1].normalized()
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct ColorCodesFromBytes<T>
where
T: Iterator<Item = u8>,
{
bytes: T,
}
impl<T> ColorCodesFromBytes<T>
where
T: Iterator<Item = u8>,
{
fn next_header(&mut self) -> Option<Result<(), String>> {
match self.bytes.next() {
Some(byte) => {
if byte == CODE_START {
match self.bytes.next() {
Some(byte) => {
if byte as char == NUMBER_PREFIX {
Some(Ok(()))
} else {
Some(Err(format!("Invalid number prefix: {}", byte)))
}
}
None => Some(Err(UNEXPECTED_TERMINATION_MSG.to_string())),
}
} else {
Some(Err(format!("Invalid start byte: {}", byte)))
}
}
None => None,
}
}
fn read_digits(&mut self) -> Result<String, String> {
let mut digits = String::new();
for count in 0..=MAX_DIGITS {
match self.bytes.next() {
Some(byte) => {
if byte.is_ascii_digit() {
if count < MAX_DIGITS {
digits.push(byte as char);
} else {
return Err(format!("Expected at most {} digits", MAX_DIGITS));
}
} else if byte as char == NUMBER_SUFFIX {
return if digits.is_empty() {
Err("Expected at least one digit".to_string())
} else {
Ok(digits)
};
} else {
return Err(format!("Encountered Unexpected byte \"{}\"", byte));
}
}
None => return Err(UNEXPECTED_TERMINATION_MSG.to_string()),
}
}
Ok(digits)
}
fn parse_color_code(&mut self) -> Result<u8, String> {
let digits = self.read_digits()?;
self.bytes.next(); // Discard bg-color encoded char
match digits.parse::<u8>() {
Ok(number) => Ok(number),
Err(_) => Err(format!("Could not parse u8 from {}", digits)),
}
}
}
impl<T> From<T> for ColorCodesFromBytes<T>
where
T: Iterator<Item = u8>,
{
fn from(bytes: T) -> Self {
Self { bytes }
}
}
impl<T> Iterator for ColorCodesFromBytes<T>
where
T: Iterator<Item = u8>,
{
type Item = Result<ColorCode, String>;
fn next(&mut self) -> Option<Self::Item> {
if let Err(msg) = self.next_header()? {
return Some(Err(msg));
}
match self.parse_color_code() {
Ok(sum) => {
if sum == 0 {
None
} else {
Some(ColorCode::new(sum))
}
}
Err(msg) => Some(Err(format!("{} while parsing color code", msg))),
}
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct ColorCodesToBytes<T>
where
T: Iterator<Item = Result<ColorCode, String>>,
{
codes: T,
}
impl<T> From<T> for ColorCodesToBytes<T>
where
T: Iterator<Item = Result<ColorCode, String>>,
{
fn from(codes: T) -> Self {
Self { codes }
}
}
impl<T> Iterator for ColorCodesToBytes<T>
where
T: Iterator<Item = Result<ColorCode, String>>,
{
type Item = Result<u8, String>;
fn next(&mut self) -> Option<Self::Item> {
match self.codes.next() {
Some(high) => match high {
Ok(high) => match self.codes.next() {
Some(low) => match low {
Ok(low) => Some(Ok(u8::from_color_codes([high, low]))),
Err(msg) => Some(Err(msg)),
},
None => Some(Err("Missing second color code block".to_string())),
},
Err(msg) => Some(Err(msg)),
},
None => None,
}
}
}
src/main.rs
use ansi_color_codec::ColorCodec;
use clap::Parser;
use ctrlc::set_handler;
use std::io::{stdin, stdout, Read, Write};
use std::process::exit;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
const STDOUT_WRITE_ERR: &str = "Could not write bytes to STDOUT";
#[derive(Parser)]
#[clap(about, author, version)]
struct Args {
#[clap(short, long, name = "decode")]
pub decode: bool,
#[clap(short, long, name = "no-clear")]
pub no_clear: bool,
}
fn main() {
let args = Args::parse();
let running = Arc::new(AtomicBool::new(true));
let bytes = stream_stdin(running.clone());
set_handler(move || {
running.store(false, Ordering::SeqCst);
})
.expect("Error setting Ctrl-C handler");
if args.decode {
decode(bytes)
} else {
encode(bytes, !args.no_clear)
}
}
fn decode(bytes: impl Iterator<Item = u8>) {
for result in bytes.ansi_color_decode() {
match result {
Ok(byte) => {
stdout().write_all(&[byte]).expect(STDOUT_WRITE_ERR);
}
Err(msg) => {
eprintln!("{}", msg);
exit(1);
}
}
}
stdout().flush().expect("Could not flush STDOUT")
}
fn encode(bytes: impl Iterator<Item = u8>, clear: bool) {
for code in bytes.ansi_color_encode() {
stdout()
.write_all(code.to_string().as_bytes())
.expect(STDOUT_WRITE_ERR);
}
if clear {
println!("\x1b[0m ");
}
}
fn stream_stdin(running: Arc<AtomicBool>) -> impl Iterator<Item = u8> {
stdin()
.bytes()
.take_while(move |byte| byte.is_ok() && running.load(Ordering::SeqCst))
.map(|byte| byte.unwrap())
}
However, when I run
> echo "Windows doing Windows stuff" | ansi-color-codec | ansi-color-codec -d
on Windows, the program fails with
Invalid start byte: 239
When I inspect the first (three) bytes, I can see that ansi-color-codec -d receives the UTF-8 BOM from ansi-color-codec. But why? My program does not print it and only puts raw bytes onto STDOUT
Found the answer on Reddit:
EDIT : [SOLVED]
CAUSE : Windows powershell (at least) uses different code page from external programs ( rust program in this case ) which caused inconsistent inter process communication.
SOLUTION : Set the following environment variable for consistent communication with rust programs.
$OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding

strange process names when trying to get a PID in rust with the Windows api

Hello my goal is to create a rust function which takes a process name as string and returns a PID.
I came up with this function:
pub unsafe fn get_proc_id(proc_name: String) -> u32 {
let mut proc_id: u32 = 0;
let mut h_snap = windows::Win32::System::Diagnostics::ToolHelp::CreateToolhelp32Snapshot(
TH32CS_SNAPPROCESS,
0,
);
let h_snap = match h_snap {
Ok(t) => t,
Err(e) => panic!("eror {}", e),
};
let mut proc_entry: PROCESSENTRY32 = PROCESSENTRY32 {
..PROCESSENTRY32::default()
};
proc_entry.dwSize = std::mem::size_of::<PROCESSENTRY32>() as u32;
let entry_ptr = &mut proc_entry as *mut PROCESSENTRY32;
if windows::Win32::System::Diagnostics::ToolHelp::Process32First(h_snap, entry_ptr).as_bool() {
loop {
let mut proc_exe_string: String = String::new();
if proc_exe_string.eq(&proc_name) {
proc_id = proc_entry.th32ProcessID;
break;
}
for e in proc_entry.szExeFile {
if e.0 != 0 {
proc_exe_string.push(e.0 as char)
}
}
println!("{}", proc_exe_string);
if !Process32Next(h_snap, entry_ptr).as_bool() {
break;
}
}
}
CloseHandle(h_snap);
return proc_id; }
The function prints some strange process names. for example I'm looking for "ac_client.exe" however the function shows this process as ac_client.exeexe.exeee and this is similar for most process names. some other examples:
chrome.exexeexe.exeee
Discord.exer.exee.exee

What's the idiomatic replacement for glsl output parameters in wgsl?

In glsl and hlsl, I can define a function like this:
float voronoi(vec2 x, out int2 cell) {
cell = ...
return ...
}
However, it doesn't seem like this is possible in wgsl.
What's the intended replacement for this? I guess I could define a VoronoiResult struct, but it seems overly boilerplate heavy:
struct VoronoiResult {
cell: vec2<i32>;
distance: f32;
};
fn voronoi(x: vec2<f32>) -> VoronoiResult {
// ...
var ret: VoronoiResult;
ret.distance = distance;
ret.cell = cell;
return ret;
}
The equivalent would be to use a pointer argument:
fn voronoi(x: vec2<f32>, cell: ptr<function, vec2<i32>>) -> f32 {
*cell = vec2(1, 2);
return 1.f;
}
#compute #workgroup_size(1)
fn main() {
var a: vec2<i32>;
var f = voronoi(vec2(1.f, 1.f), &a);
}
This produces the HLSL:
float voronoi(float2 x, inout int2 cell) {
cell = int2(1, 2);
return 1.0f;
}
[numthreads(1, 1, 1)]
void main() {
int2 a = int2(0, 0);
float f = voronoi((1.0f).xx, a);
return;
}
You can also make the struct version shorter by using the struct initializer:
struct Out {
cell: vec2<i32>,
val: f32,
}
fn voronoi(x: vec2<f32>) -> Out {
return Out(vec2(1, 2), 1.f);
}
#compute #workgroup_size(1)
fn main() {
var f = voronoi(vec2(1.f, 1.f));
}

Is there a way to do a for loop that is neither iterative nor linear?

Can I write a Rust for loop equivalent to this C code:
for(int i = 2; i <= 128; i=i*i){
//do something
}
I'm only seeing things like
for i in 0..128 { /* do something */ }
or
let v = vec![0, 1, 2, /* ... */ ];
for i in v.iter() { /* do something */ }
Should I just use a while loop?
You can always create a custom iterator that does whatever unique sequence you need:
struct Doubling {
current: u64,
max: u64,
}
impl Iterator for Doubling {
type Item = u64;
fn next(&mut self) -> Option<Self::Item> {
if self.current > self.max {
None
} else {
let v = Some(self.current);
self.current *= 2;
v
}
}
}
fn main() {
let iter = Doubling { current: 2, max: 128 };
let values: Vec<_> = iter.collect();
println!("{:?}", values);
}
It's important to recognize that this logic (like the original C!) has nasty edge cases when the value is doubled beyond the size of the type.
In this particular case, you can also recognize that you have an exponential series:
fn main() {
let iter = (1..8).map(|p| 2i32.pow(p));
let values: Vec<_> = iter.collect();
println!("{:?}", values);
}
If you want to get really experimental, check out Lazy sequence generation in Rust. Adapted here:
#![feature(generators, generator_trait, conservative_impl_trait)]
use std::ops::{Generator, GeneratorState};
fn doubling(mut start: u64, max: u64) -> impl Iterator<Item = u64> {
GeneratorIteratorAdapter(move || {
while start <= max {
yield start;
start *= 2;
}
})
}
fn main() {
let iter = doubling(2, 128);
let sum: Vec<_> = iter.collect();
println!("{:?}", sum);
}
/* copy-pasta */
struct GeneratorIteratorAdapter<G>(G);
impl<G> Iterator for GeneratorIteratorAdapter<G>
where
G: Generator<Return = ()>,
{
type Item = G::Yield;
fn next(&mut self) -> Option<Self::Item> {
match self.0.resume() {
GeneratorState::Yielded(x) => Some(x),
GeneratorState::Complete(_) => None,
}
}
}
can I write a for loop equivalent to this C code:
That specifically, yes:
extern crate itertools;
for i in itertools::iterate(2, |&i| i*i).take_while(|&i| i <= 128) {
// do something
}
But in general, no. There is no single, direct equivalent to all possible uses of C's for loop. If there's no way to write it using iterators then yes, you need to use a more general loop form:
{
let mut i = 2;
while i <= 128 {
// do something
i = i*i;
}
}

Resources