How to initialize variadic function arguments in Zig? - variadic-functions

What is the proper way to use and initialise variadic arguments in Zig functions?
fn variadicFunc(val: u8, variadicArg: ...u8) {
for (variadicArg) |arg| {
// ... work on the arg
_ = arg;
}
}

Answering my own question, thanks to Aiz and Hanna from Zig Discord:
The most basic way to write variadicFunction in Zig is to use anytype and anonymous structs:
fn variadicFunc(variadicArg: anytype) {
for (std.meta.fields(#TypeOf(items)) |field| {
const value = #field(items, field.name);
// work with the value
}
}
variadicFunc(.{"Hello", 12, .{ Hello } });
But be careful. This will create a binary bloat. Use arrays or slices whenever possible.

It is possible with anytype and #call.
pub extern "c" fn printf(format: [*:0]const u8, ...) c_int;
const std = #import("std");
fn call_printf(fmt: [*:0]const u8, args: anytype) c_int {
return #call(.{}, std.c.printf, .{fmt} ++ args);
}
pub fn main() anyerror!void {
_ = call_printf("All your codebase are belong to %s.", .{"us"});
}

Related

Create a vector with macro iterator syntax

How can I create a new vector with the iterator Rust macro syntax?
I am trying this:
unsafe {
MUT_STATIC_VAR = vec![
#(#my_outher_vector_data)*,
];
}
Full explanation: I am trying to reasign data that I write in one mut static var of type: Vec when the macro it's spanded at compile time. When I try to retrieve the data at runtime, the global it's empty, so I am rewiring the data that I want in main().
Recap. I am just want to assign the content of one vector to another, but neither array or Vec<T> implements ToTokens.
Compiler error:
`main` function not found in crate `my_crate`
Thanks
To initialize the content, Iterators are able to use macro #(#...)*, syntax.
let other_as_iter = my_outher_vector_data.iter();
quote {
unsafe {
MUT_STATIC_VAR = vec![
#(#other_as_iter)*,
];
}
}
I think lazy_static should do the job:
#[macro_use]
extern crate lazy_static;
use std::sync::Mutex;
lazy_static! {
static ref MUT_STATIC_VAR: Mutex<Vec<String>> = Mutex::new(vec![]);
}
fn other_vec(v: Vec<String>) {
let mut r = MUT_STATIC_VAR.lock().unwrap();
r.extend_from_slice(v.as_slice());
}
fn main() {
other_vec(vec!["dog".to_string(), "cat".to_string(), "mouse".to_string()]);
}
…or draining the other vec after initializing MUT_STATIC_VAR:
fn other_vec(v: &mut Vec<String>) {
let mut r = MUT_STATIC_VAR.lock().unwrap();
r.extend_from_slice(v.drain(..).as_slice());
}
fn main() {
other_vec(&mut vec!["dog".to_string(), "cat".to_string(), "mouse".to_string()]);
}
…or my_other_vector_data wrapped in other_vec! macro:
Playground
macro_rules! other_vec {
() => {
vec!["dog", "cat", "mouse"] // my_other_vector_data here
};
}

How can I pass a pointer to itself to C++ so it can perform a callback?

I've defined a way to pass my Rust object to C++ so it can call this Rust object back:
extern "C" {
pub fn zlmedia_set_parent(zl_media: *mut ZLInstance, parent: Box<ZLMedia>);
}
pub fn new_boxed(url: &str) -> Box<ZLMedia> {
let c_url = CString::new(url).expect("CString::new failed");
let p = Box::new(ZLMedia {
zl_media: unsafe { zlmedia_new(c_url.into_raw()) },
url: url.to_string(),
});
unsafe {
zlmedia_set_parent(p.as_ref().zl_media, p);
}
p
}
The problem is that I can't pass the Box to C++ because I move it here:
unsafe {
zlmedia_set_parent(p.as_ref().zl_media, p);
}
How can I pass a Box to itself to C++ and still return it in the new? I don't really need to move it, because it goes to a C++ function.
If you want the ZLMedia to be owned by the Rust code then you can pass a pointer to it rather then the box itself.
use std::borrow::Borrow as _;
extern "C" {
pub fn zlmedia_set_parent(zl_media: *mut ZLInstance, parent: *const ZLMedia);
}
pub fn new_boxed(url: &str) -> Box<ZLMedia> {
let c_url = CString::new(url).expect("CString::new failed");
let p = Box::new(ZLMedia {
zl_media: unsafe { zlmedia_new(c_url.into_raw()) },
url: url.to_string(),
});
unsafe {
zlmedia_set_parent(p.as_ref().zl_media, p.borrow() as *const ZLMedia);
}
p
}
If the C++ code dereferences the pointer after the box is dropped, it will trigger Undefined Behaviour. If the C++ code tries to free the pointer then it's also UB. It's up to you to make sure that these things don't happen.

Rust "if let" not working?

I am wrapping libxml2 in Rust as an exercise in learning the Rust FFI, and I have come across something strange. I am new to Rust, but I believe the following should work.
In main.rs I have:
mod xml;
fn main() {
if let doc = xml::parse_file("filename") {
doc.simple_function();
}
}
And xml.rs is:
extern create libc;
use libc::{c_void, c_char, c_int, c_ushort};
use std::ffi::CString;
// There are other struct definitions I've implemented that xmlDoc
// depends on, but I'm not going to list them because I believe
// they're irrelevant
#[allow(non_snake_case)]
#[allow(non_camel_case_types)]
#[repr(C)]
struct xmlDoc {
// xmlDoc structure defined by the libxml2 API
}
pub struct Doc {
ptr: *mut xmlDoc
}
impl Doc {
pub fn simple_function(&self) {
if self.ptr.is_null() {
println!("ptr doesn't point to anything");
} else {
println!("ptr is not null");
}
}
}
#[allow(non_snake_case)]
#[link(name = "xml2")]
extern {
fn xmlParseFile(filename: *const c_char) -> *mut xmlDoc;
}
pub fn parse_file(filename: &str) -> Option<Doc> {
unsafe {
let result;
match CString::new(filename) {
Ok(f) => { result = xmlParseFile(f.as_ptr()); },
Err(_) => { return None; }
}
if result.is_null() {
return None;
}
Some(Doc { ptr: result })
}
}
I'm wrapping the C struct, xmlDoc in a nice Rust-friendly struct, Doc, to have a clear delineation between the safe (Rust) and unsafe (C) data types and functions.
This all works for the most part except when I compile, I get an error in main.rs:
src/main.rs:38:13: 38:28 error: no method named 'simple_function' found
for type 'std::option::Option<xml::Doc>' in the current scope
src/main.rs:38 doc.simple_function();
^~~~~~~~~~~~~~~
error: aborting due to previous error`
It seems convinced that doc is an Option<xml::Doc> even though I'm using the if let form that should unwrap the Option type. Is there something I'm doing incorrectly?
match xml::parse_file("filename") {
Some(doc) => doc.simple_function(),
None => {}
}
The above works fine, but I'd like to use the if let feature of Rust if I'm able.
You need to pass the actual pattern to if let (unlike languages like Swift which special case if let for Option types):
if let Some(doc) = xml::parse_file("filename") {
doc.simple_function();
}

How can I create enums with constant values in Rust?

I can do this:
enum MyEnum {
A(i32),
B(i32),
}
but not this:
enum MyEnum {
A(123), // 123 is a constant
B(456), // 456 is a constant
}
I can create the structures for A and B with a single field and then implement that field, but I think there might be an easier way. Is there any?
The best way to answer this is working out why you want constants in an enum: are you associating a value with each variant, or do you want each variant to be that value (like an enum in C or C++)?
For the first case, it probably makes more sense to just leave the enum variants with no data, and make a function:
enum MyEnum {
A,
B,
}
impl MyEnum {
fn value(&self) -> i32 {
match *self {
MyEnum::A => 123,
MyEnum::B => 456,
}
}
}
// call like some_myenum_value.value()
This approach can be applied many times, to associate many separate pieces of information with each variant, e.g. maybe you want a .name() -> &'static str method too. In the future, these functions can even be marked as const functions.
For the second case, you can assign explicit integer tag values, just like C/C++:
enum MyEnum {
A = 123,
B = 456,
}
This can be matched on in all the same ways, but can also be cast to an integer MyEnum::A as i32. (Note that computations like MyEnum::A | MyEnum::B are not automatically legal in Rust: enums have specific values, they're not bit-flags.)
Creating an "enum" with constant values, can be augmented using structs and associated constants.
This is similar to how crates like bitflags works and what it would generate.
Additionally, to prevent direct instantiation of MyEnum you can tag it with #[non_exhaustive].
#[non_exhaustive]
struct MyEnum;
impl MyEnum {
pub const A: i32 = 123;
pub const B: i32 = 456;
}
Then you simply use the "enum" as you otherwise would, by accessing MyEnum::A and MyEnum::B.
People looking at this may stumble upon the introduction and deprecation of FromPrimitive. A possible replacement which might also be useful here is enum_primitive. It allows you to use C-like enums and have them cast between numeric and logical representation:
#[macro_use]
extern crate enum_primitive;
extern crate num;
use num::FromPrimitive;
enum_from_primitive! {
#[derive(Debug, PartialEq)]
enum FooBar {
Foo = 17,
Bar = 42,
Baz,
}
}
fn main() {
assert_eq!(FooBar::from_i32(17), Some(FooBar::Foo));
assert_eq!(FooBar::from_i32(42), Some(FooBar::Bar));
assert_eq!(FooBar::from_i32(43), Some(FooBar::Baz));
assert_eq!(FooBar::from_i32(91), None);
}
The enum-map crate provides the ability to assign a value to the enum record. What is more, you can use this macro with different value types.
use enum_map::{enum_map, Enum}; // 0.6.2
#[derive(Debug, Enum)]
enum Example {
A,
B,
C,
}
fn main() {
let mut map = enum_map! {
Example::A => 1,
Example::B => 2,
Example::C => 3,
};
map[Example::C] = 4;
assert_eq!(map[Example::A], 1);
for (key, &value) in &map {
println!("{:?} has {} as value.", key, value);
}
}
How about this?
enum MyEnum {
A = 123,
B = 456,
}
assert_eq!(MyEnum::A as i32, 123i32);
assert_eq!(MyEnum::B as i32, 456i32);
Just to give another idea.
#[allow(non_snake_case, non_upper_case_globals)]
mod MyEnum {
pub const A: i32 = 123;
pub const B: i32 = 456;
}
Then you can simply use it by accessing MyEnum::A and MyEnum::B or use MyEnum::*.
The advantage of doing this over associated constants is that you can even nest more enums.
#[allow(non_snake_case, non_upper_case_globals)]
mod MyEnum {
pub const A: i32 = 123;
pub const B: i32 = 456;
#[allow(non_snake_case, non_upper_case_globals)]
mod SubEnum {
pub const C: i32 = 789;
}
}
For my project I wrote a macro that automatically generates indexes and sets initial values.
#[macro_export]
macro_rules! cnum {
(#step $_idx:expr,) => {};
(#step $idx:expr, $head:ident, $($tail:ident,)*) => {
pub const $head: usize = $idx;
cnum!(#step $idx + 1usize, $($tail,)*);
};
($name:ident; $($n:ident),* $(,)* $({ $($i:item)* })?) => {
cnum!($name; 0usize; $($n),* $({ $($i)* })?);
};
($name:ident; $start:expr; $($n:ident),* $(,)* $({ $($i:item)* })?) => {
#[macro_use]
#[allow(dead_code, non_snake_case, non_upper_case_globals)]
pub mod $name {
use crate::cnum;
$($($i)*)?
cnum!(#step $start, $($n,)*);
}
};
}
Then you can use it like this,
cnum! { Tokens;
EOF,
WhiteSpace,
Identifier,
{
cnum! { Literal; 100;
Numeric,
String,
True,
False,
Nil,
}
cnum! { Keyword; 200;
For,
If,
Return,
}
}
}
I have created a crate enumeration just for this.
Example using my crate:
use enumeration::prelude::*;
enumerate!(MyEnum(u8; i32)
A = 123
B = 456
);
pub fn main() {
assert_eq!(*MyEnum::A.value(), 123);
assert_eq!(*MyEnum::B.value(), 456);
}

"Registering" trait implementations + factory method for trait objects

Say we want to have objects implementations switched at runtime, we'd do something like this:
pub trait Methods {
fn func(&self);
}
pub struct Methods_0;
impl Methods for Methods_0 {
fn func(&self) {
println!("foo");
}
}
pub struct Methods_1;
impl Methods for Methods_1 {
fn func(&self) {
println!("bar");
}
}
pub struct Object<'a> { //'
methods: &'a (Methods + 'a),
}
fn main() {
let methods: [&Methods; 2] = [&Methods_0, &Methods_1];
let mut obj = Object { methods: methods[0] };
obj.methods.func();
obj.methods = methods[1];
obj.methods.func();
}
Now, what if there are hundreds of such implementations? E.g. imagine implementations of cards for collectible card game where every card does something completely different and is hard to generalize; or imagine implementations for opcodes for a huge state machine. Sure you can argue that a different design pattern can be used -- but that's not the point of this question...
Wonder if there is any way for these Impl structs to somehow "register" themselves so they can be looked up later by a factory method? I would be happy to end up with a magical macro or even a plugin to accomplish that.
Say, in D you can use templates to register the implementations -- and if you can't for some reason, you can always inspect modules at compile-time and generate new code via mixins; there are also user-defined attributes that can help in this. In Python, you would normally use a metaclass so that every time a new child class is created, a ref to it is stored in the metaclass's registry which allows you to look up implementations by name or parameter; this can also be done via decorators if implementations are simple functions.
Ideally, in the example above you would be able to create Object as
Object::new(0)
where the value 0 is only known at runtime and it would magically return you an Object { methods: &Methods_0 }, and the body of new() would not have the implementations hard-coded like so "methods: [&Methods; 2] = [&Methods_0, &Methods_1]", instead it should be somehow inferred automatically.
So, this is probably extremely buggy, but it works as a proof of concept.
It is possible to use Cargo's code generation support to make the introspection at compile-time, by parsing (not exactly parsing in this case, but you get the idea) the present implementations, and generating the boilerplate necessary to make Object::new() work.
The code is pretty convoluted and has no error handling whatsoever, but works.
Tested on rustc 1.0.0-dev (2c0535421 2015-02-05 15:22:48 +0000)
(See on github)
src/main.rs:
pub mod implementations;
mod generated_glue {
include!(concat!(env!("OUT_DIR"), "/generated_glue.rs"));
}
use generated_glue::Object;
pub trait Methods {
fn func(&self);
}
pub struct Methods_2;
impl Methods for Methods_2 {
fn func(&self) {
println!("baz");
}
}
fn main() {
Object::new(2).func();
}
src/implementations.rs:
use super::Methods;
pub struct Methods_0;
impl Methods for Methods_0 {
fn func(&self) {
println!("foo");
}
}
pub struct Methods_1;
impl Methods for Methods_1 {
fn func(&self) {
println!("bar");
}
}
build.rs:
#![feature(core, unicode, path, io, env)]
use std::env;
use std::old_io::{fs, File, BufferedReader};
use std::collections::HashMap;
fn main() {
let target_dir = Path::new(env::var_string("OUT_DIR").unwrap());
let mut target_file = File::create(&target_dir.join("generated_glue.rs")).unwrap();
let source_code_path = Path::new(file!()).join_many(&["..", "src/"]);
let source_files = fs::readdir(&source_code_path).unwrap().into_iter()
.filter(|path| {
match path.str_components().last() {
Some(Some(filename)) => filename.split('.').last() == Some("rs"),
_ => false
}
});
let mut implementations = HashMap::new();
for source_file_path in source_files {
let relative_path = source_file_path.path_relative_from(&source_code_path).unwrap();
let source_file_name = relative_path.as_str().unwrap();
implementations.insert(source_file_name.to_string(), vec![]);
let mut file_implementations = &mut implementations[*source_file_name];
let mut source_file = BufferedReader::new(File::open(&source_file_path).unwrap());
for line in source_file.lines() {
let line_str = match line {
Ok(line_str) => line_str,
Err(_) => break,
};
if line_str.starts_with("impl Methods for Methods_") {
const PREFIX_LEN: usize = 25;
let number_len = line_str[PREFIX_LEN..].chars().take_while(|chr| {
chr.is_digit(10)
}).count();
let number: i32 = line_str[PREFIX_LEN..(PREFIX_LEN + number_len)].parse().unwrap();
file_implementations.push(number);
}
}
}
writeln!(&mut target_file, "use super::Methods;").unwrap();
for (source_file_name, impls) in &implementations {
let module_name = match source_file_name.split('.').next() {
Some("main") => "super",
Some(name) => name,
None => panic!(),
};
for impl_number in impls {
writeln!(&mut target_file, "use {}::Methods_{};", module_name, impl_number).unwrap();
}
}
let all_impls = implementations.values().flat_map(|impls| impls.iter());
writeln!(&mut target_file, "
pub struct Object;
impl Object {{
pub fn new(impl_number: i32) -> Box<Methods + 'static> {{
match impl_number {{
").unwrap();
for impl_number in all_impls {
writeln!(&mut target_file,
" {} => Box::new(Methods_{}),", impl_number, impl_number).unwrap();
}
writeln!(&mut target_file, "
_ => panic!(\"Unknown impl number: {{}}\", impl_number),
}}
}}
}}").unwrap();
}
The generated code:
use super::Methods;
use super::Methods_2;
use implementations::Methods_0;
use implementations::Methods_1;
pub struct Object;
impl Object {
pub fn new(impl_number: i32) -> Box<Methods + 'static> {
match impl_number {
2 => Box::new(Methods_2),
0 => Box::new(Methods_0),
1 => Box::new(Methods_1),
_ => panic!("Unknown impl number: {}", impl_number),
}
}
}

Resources