Anonymous Enum and Struct types in Rust - rust

We have anonymous function types (closures) and tuple types in Rust, e.g.
let t = (34, "Hello", false);
let f = |a: usize| a*2;
I imagine there also could be anonymous enum and struct types, e.g.
let s = struct {name: "Hello", age: 34};
let e = enum {Knight, King, Queen}::King;
Why was the design decision made to not include anonymous enum and struct types?
Does it have something to do with the automatized and non-guaranteed memory layout of structs? I guess in the enum case access to the variants might also be an issue if the type itself is anonymous? Are there RFCs that address these features?

Something like
macro_rules! astruct {
() => {};
($($i:ident: $t:ty = $val:expr),+) => {{
struct Inner {$(pub $i: $t),+}
Inner {$($i: $val),+}
}};
}
let foo = astruct!{
x: i32 = -45,
y: u8 = 19,
};
let bar = astruct!{
z: i32 = -45
};
assert_eq!(foo.x, bar.z);
assert_eq!(foo.y, 19);

Related

Explain this struct implementation in Rust

// `Inches`, a tuple struct that can be printed
#[derive(Debug)]
struct Inches(i32);
impl Inches {
fn to_centimeters(&self) -> Centimeters {
let &Inches(inches) = self;
Centimeters(inches as f64 * 2.54)
}
}
I understand that the function signature takes a reference of the Inches struct as a parameter, what does the first line in the function definition mean?
In the let a = b syntax, a doesn't just have to be an indentifier for a new variable, it can also be a pattern much like in match arms:
let a = 0;
let (a, c) = (0, 1);
let &a = &0;
let Inches(a) = Inches(0);
So what you see here is self being matched as a &Inches and pulling out the inner value into a new variable called "inches".
This statement is probably more universally readable as:
let inches = self.0;

Parse String to most appropriate type automatically

How to parse some string to most appropriate type?
I know there is .parse::<>() method, but you need to specify type in advance like this:
fn main() {
let val = String::from("54");
assert_eq!(val.parse::<i32>().unwrap(), 54i32);
let val = String::from("3.14159");
assert_eq!(val.parse::<f32>().unwrap(), 3.14159f32);
let val = String::from("Hello!");
assert_eq!(val.parse::<String>().unwrap(), "Hello!".to_string());
}
But I need something like this:
fn main() {
let val = String::from("54");
assert_eq!(val.generic_parse().unwrap(), 54i32); // or 54i16 or 54 u32 or etc ...
let val = String::from("3.14159");
assert_eq!(val.generic_parse().unwrap(), 3.14159f32);
let val = String::from("Hello!");
assert_eq!(val.generic_parse().unwrap(), "Hello!".to_string());
}
Is there an appropriate crate for something like this? I don't want to re-invent the wheel for the umpteenth time.
EDIT
This is what I actually want to do:
struct MyStruct<T> {
generic_val: T,
}
fn main() {
let val = String::from("54");
let b = MyStruct {generic_val: val.parse().unwrap()};
let val = String::from("3.14159");
let b = MyStruct {generic_val: val.parse().unwrap()};
}
Error:
error[E0282]: type annotations needed for `MyStruct<T>`
--> src/main.rs:7:13
|
7 | let b = MyStruct {generic_val: val.parse().unwrap()};
| - ^^^^^^^^ cannot infer type for type parameter `T` declared on the struct `MyStruct`
| |
| consider giving `b` the explicit type `MyStruct<T>`, where the type parameter `T` is specified
You need to base things on the right Enum type and implement FromStr for it. Like this.
#[derive(PartialEq, Debug)]
enum Val {
Isize(isize),
F64(f64),
}
impl core::str::FromStr for Val {
type Err = & 'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match (s.parse::<isize>(), s.parse::<f64>()) {
(Ok(i),_) => Ok(Val::Isize(i)),
(Err(_), Ok(f)) => Ok(Val::F64(f)),
(Err(_), Err(_)) => Err("neither parser worked"),
}
}
}
fn main() {
assert_eq!("34".parse(), Ok(Val::Isize(34)));
assert_eq!("12.3".parse(), Ok(Val::F64(12.3)));
assert!("wrong".parse::<Val>().is_err());
}
Rust is a statically typed language. This means that the compiler needs to know the type of variables at compile time. There are three ways things can go from there:
If your strings are known at compile-time, then you might as well replace them with literal values in your code (eg. "54" → 54).
If you have some other way of knowing at compile time what type a given string should parse to, then you can specify the appropriate type when parsing the string: let a = "54".parse::<i32>().unwrap()
If your strings are only known at run-time and you want to autodetect the type, then you need to use some kind of enumerated value that will store the type alongside the value in your program:
use std::str::FromStr;
enum Value {
I32 (i32),
F32 (f32),
String (String),
}
impl Value {
fn new (s: &str) -> Value {
if let Ok (v) = s.parse::<i32>() {
Value::I32 (v)
} else if let Ok (v) = s.parse::<f32>() {
Value::F32 (v)
} else {
Value::String (s.into())
}
}
}
That way, the rest of your code will have a way of knowing what type was detected and to adjust its processing accordingly.

What is this strange syntax where an enum variant is used as a function?

Below is the example given by the mod documentation of syn::parse.
enum Item {
Struct(ItemStruct),
Enum(ItemEnum),
}
struct ItemStruct {
struct_token: Token![struct],
ident: Ident,
brace_token: token::Brace,
fields: Punctuated<Field, Token![,]>,
}
impl Parse for Item {
fn parse(input: ParseStream) -> Result<Self> {
let lookahead = input.lookahead1();
if lookahead.peek(Token![struct]) {
input.parse().map(Item::Struct) // <-- here
} else if lookahead.peek(Token![enum]) {
input.parse().map(Item::Enum) // <-- and here
} else {
Err(lookahead.error())
}
}
}
Is input.parse().map(Item::Struct) a valid normal Rust syntax (appears not as Item::Struct is not a function), or is it a kind of special syntax for proc_macro libs? If the latter is the case, is there a documentation of the proc_macro specific syntax rules?
This syntax is standard Rust syntax. You can use tuple struct or tuple struct-like enum variants as functions. See this small example:
enum Color {
Str(String),
Rgb(u8, u8, u8),
}
struct Foo(bool);
// Use as function pointers (type annotations not necessary)
let f: fn(String) -> Color = Color::Str;
let g: fn(u8, u8, u8) -> Color = Color::Rgb;
let h: fn(bool) -> Foo = Foo;
In the next example, those functions are directly passed to another function (like Option::map) (Playground):
// A function which takes a function
fn string_fn<O, F>(f: F) -> O
where
F: FnOnce(String) -> O,
{
f("peter".to_string())
}
string_fn(|s| println!("{}", s)); // using a clojure
string_fn(std::mem::drop); // using a function pointer
// Using the enum variant as function
let _: Color = string_fn(Color::Str);
You can find out more about this feature, in this chapter of the book.

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

Is there an easy way to cast entire tuples of scalar values at once?

I want to cast a (u16, u16) to a (f32, f32). This is what I tried:
let tuple1 = (5u16, 8u16);
let tuple2 = tuple1 as (f32, f32);
Ideally, I would like to avoid writing
let tuple2 = (tuple1.0 as f32, tuple1.1 as f32);
There's no built-in way to do this, but one can do it with a macro:
macro_rules! tuple_as {
($t: expr, ($($ty: ident),*)) => {
{
let ($($ty,)*) = $t;
($($ty as $ty,)*)
}
}
}
fn main() {
let t: (u8, char, isize) = (97, 'a', -1);
let other = tuple_as!(t, (char, i32, i8));
println!("{:?}", other);
}
Prints ('a', 97, -1).
The macro only works for casting between types with names that are a single identifier (that's what the : ident refers to), since it reuses those names for binding to the elements of the source tuple to be able to cast them. All primitive types are valid single identifiers, so it works well for those.
No, you cannot. This is roughly equivalent to "can I cast all the fields in a struct to different types all at once?".
You can write a generic extension trait which can do this conversion for you, the only problem is that I don't believe there's any existing generic "conversion" trait which also has a u16 -> f32 implementation defined.
If you really want a function that does this, here is an as-minimal-as-I-could-make-it skeleton you can build on:
trait TupleCast<T> {
type Output;
fn tuple_cast(self) -> <Self as TupleCast<T>>::Output;
}
impl<T> TupleCast<T> for () {
type Output = ();
fn tuple_cast(self) -> <() as TupleCast<T>>::Output {
()
}
}
impl<S, T> TupleCast<T> for (S,) where S: CustomAs<T> {
type Output = (T,);
fn tuple_cast(self) -> <(S,) as TupleCast<T>>::Output {
(self.0.custom_as(),)
}
}
impl<S, T> TupleCast<T> for (S, S) where S: CustomAs<T> {
type Output = (T, T);
fn tuple_cast(self) -> <(S, S) as TupleCast<T>>::Output {
(self.0.custom_as(), self.1.custom_as())
}
}
// You would probably have more impls, up to some size limit.
// We can't use std::convert::From, because it isn't defined for the same
// basic types as the `as` operator is... which kinda sucks. So, we have
// to implement the desired conversions ourselves.
//
// Since this would be hideously tedious, we can use a macro to speed things
// up a little.
trait CustomAs<T> {
fn custom_as(self) -> T;
}
macro_rules! custom_as_impl {
($src:ty:) => {};
($src:ty: $dst:ty) => {
impl CustomAs<$dst> for $src {
fn custom_as(self) -> $dst {
self as $dst
}
}
};
($src:ty: $dst:ty, $($rest:ty),*) => {
custom_as_impl! { $src: $dst }
custom_as_impl! { $src: $($rest),* }
};
}
// You could obviously list others, or do manual impls.
custom_as_impl! { u16: u16, u32, u64, i32, i64, f32, f64 }
fn main() {
let x: (u16, u16) = (1, 2);
let y: (f32, f32) = x.tuple_cast();
println!("{:?}", y);
}
No,
there
is
not.
this version handles a few more cases Playground Example
original source: https://stackoverflow.com/a/29981602/5979634
because of matching rules, for single type casts just use as_tuple!(expr, T) or as_tuple!(expr, (T))
the rest works as in the original answer
macro_rules! tuple_as {
($t: expr, $ty: ident) => {{
let (a, b) = $t;
let a = a as $ty;
let b = b as $ty;
(a, b)
}};
($t: expr, ($ty: ident)) => {{
let (a, b) = $t;
let a = a as $ty;
let b = b as $ty;
(a, b)
}};
($t: expr, ($($ty: ident),*)) => {{
let ($($ty,)*) = $t;
($($ty as $ty,)*)
}}}

Resources