Nested constants in Rust - nested

In Ruby, I can do this:
module Settings
module General
SomeSetting = "Some value"
end
end
puts Settings::General::SomeSetting;
# => "Some value"
How do I achieve the same thing in Rust?
I want to have some hard-coded values and I don't want to have to declare a struct that I can then use to store the settings when I'm only ever going to create that struct once.
I've tried looking but I'm unable to find something definitive.
Is it something as simple as:
settings.rs:
pub mod dungeon {
pub mod general {
pub mod room {
const MinSize: i32 = 6;
const MaxSize: i32 = 10;
const MaxNo: i32 = 30;
}
pub mod lighting {
const FovWalls: bool = true;
const TorchRadius: i32 = 10;
}
pub mod monster {
const MaxNo: i32 = 3;
}
}
}
which would allow something like
&settings::dungeon::general::room::MaxNo

is it something as simple as
Yes. As your own code shows, you can use Rust modules just like Ruby modules to add namespacing.
You can also add constants to a struct, enum, or trait:
struct Foo;
impl Foo {
const BAR: i32 = 42;
}
fn main() {
println!("{}", Foo::BAR);
}

Related

Understanding wasm-bindgen returned objects memory management

I'm trying to return a typed object from Rust to Typescript, and I ideally don't want to have to manually manage memory (performance is not the highest priority). While doing this, I'm trying to understand the generated JS.
Rust:
#[wasm_bindgen]
pub fn retjs() -> JsValue {
// in my actual project I serialize a struct with `JsValue::from_serde`
JsValue::from_str("")
}
#[wasm_bindgen]
pub fn retstruct() -> A {
A {
a: "".to_owned(),
};
}
#[wasm_bindgen]
pub struct A {
a: String,
}
#[wasm_bindgen]
impl A {
#[wasm_bindgen]
pub fn foo(&self) -> String {
return self.a.clone();
}
}
Generated JS:
export function retjs() {
const ret = wasm.retjs();
return takeObject(ret);
}
function takeObject(idx) {
const ret = getObject(idx);
dropObject(idx);
return ret;
}
function dropObject(idx) {
if (idx < 36) return;
heap[idx] = heap_next;
heap_next = idx;
}
export function retstruct() {
const ret = wasm.retstruct();
return A.__wrap(ret);
}
// generated class A omitted for brevity. Here relevant that it has a `free()` method.
Is my understanding correct that with the JsValue the memory is completely freed automatically? And that I've to do this manually with the struct? Is there a way to get around that?
I basically just want type safety in Typescript, so when I update the struct in Rust the Typescript code is automatically updated.

How to initialize variadic function arguments in Zig?

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"});
}

Rust: specify template arguments during "use ... as" import

I'm trying to specify a template parameter of an imported class, so that I don't need to specify it each time I want to use it. Something like this:
use self::binary_heap_plus::BinaryHeap<T,MinComparator> as BinaryMinHeap<T>;
Is this possible?
Is this possible?
Yes it is possible like following:
pub type CustomResult<T> = Result<T, MyError>;
#[derive(Debug)]
pub enum MyError {
MyError1,
}
fn result_returner(prm: i32) -> CustomResult<i32> {
if prm == 1 {
Ok(5)
} else {
Err(MyError::MyError1)
}
}
And also you can make such like type name changings on import as well:
use std::collections::HashMap as CustomNamedMap;
fn main() {
let mut my_map = CustomNamedMap::new();
my_map.insert(1, 2);
println!("Value: {:?}", my_map[&1]);
}
Playground

How do I turn a ToString value into a &str at compile time?

TL;DR: Is it possible to create a const … &str from a const T where T : ToString?
I like to provide default values when I use clap. However, clap needs the default_value as &str, not as a primitive type:
pub fn default_value(self, val: &'a str) -> Self
Therefore, I cannot use a previously defined const if it is not a &str:
use clap::{App, Arg};
/// The application's default port.
pub const DEFAULT_LISTENER_PORT : u16 = 12345;
fn main () {
let matches = App::new(env!("CARGO_PKG_NAME"))
.version(env!("CARGO_PKG_VERSION"))
.arg(Arg::with_name("port")
.short("p")
.value_name("PORT")
.default_value(DEFAULT_LISTENER_PORT) // < error here
).get_matches();
…
}
The workaround is to use a &str instead:
/// The application's default port.
pub const DEFAULT_LISTENER_PORT : u16 = 12345;
// Not public, since implementation detail.
const DEFAULT_LISTENER_PORT_STR : &str = "12345";
fn main () {
let matches = App::new(env!("CARGO_PKG_NAME"))
.version(env!("CARGO_PKG_VERSION"))
.arg(Arg::with_name("port")
.short("p")
.value_name("PORT")
.default_value(DEFAULT_LISTENER_PORT_STR)
).get_matches();
…
}
However, the two constants can get easily out of sync:
/// The application's default port.
pub const DEFAULT_LISTENER_PORT : u16 = 4579;
const DEFAULT_LISTENER_PORT_STR : &str = "12345"; // whoops
Therefore, I'd like to generate the latter from the former by some magic function or macro:
/// The application's default port.
pub const DEFAULT_LISTENER_PORT : u16 = 4579;
const DEFAULT_LISTENER_PORT_STR : &str = magic!(DEFAULT_LISTENER_PORT);
Note: Since std::string::ToString::to_string isn't const, it's out of scope but would provide a workaround in main, e.g.
let port_string = DEFAULT_LISTENER_PORT.to_string();
let matches = App::new(env!("CARGO_PKG_NAME"))
.version(env!("CARGO_PKG_VERSION"))
.arg(Arg::with_name("port")
.short("p")
.value_name("PORT")
.default_value(&port_string)
).get_matches();
But that's not really ergonomic either.
Is there any standard macro or function that I'm missing, or is there no language-defined way yet to provide that functionality?
You can use a macro to define the port integer and string at the same time using stringify!:
macro_rules! define_port {
($port:expr) => {
pub const DEFAULT_LISTENER_PORT : u16 = $port;
const DEFAULT_LISTENER_PORT_STR : &str = stringify!($port);
}
}
define_port!(4579);
fn main() {
println!("{}:{}", DEFAULT_LISTENER_PORT, DEFAULT_LISTENER_PORT_STR);
}
Or, if you want a more generic one:
pub struct DefaultParam<T> {
value: T,
name: &'static str,
}
macro_rules! define {
( $name:ident : $t:ty = $val:expr ) => {
pub const $name: DefaultParam<$t> = DefaultParam {
value: $val,
name: stringify!($val),
};
}
}
define!(PORT: u32 = 1234);
fn main() {
println!("{} has the value: {}", PORT.name, PORT.value);
}

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);
}

Resources