Is there some compiler built-in functionality going on, or would it be possible to implement your own enum with its variants globally accessible with rust code alone? If yes, how?
Edit: Sorry if I wasn't clear. My Question was about Some and None, not Option. For example:
enum MyOption<T> {
MySome(T),
MyNone,
}
impl<T> MyOption<T> {
fn is_some(&self) -> bool {
match self {
Self::MySome(_) => true,
Self::MyNone => false,
}
}
}
Even from "inside", I have to tell the compiler to find them in Self. So is there a way to do it like Option and have my MySome and MyNone linked to MyOption from anywhere I write them?
Rust has a module called the "prelude", accessible at std::prelude, and all of its members are imported into every module by default.
If you define your own names that shadow names in the prelude, your names take precedence. This is common for types like Result, in the following pattern:
type Result<T> = std::result::Result<T, MyCustomError>;
Whenever this is in scope, it takes precedence over the Result type included from the prelude.
Note that some things in the prelude are treated in special ways by the compiler (for example Box has built-in functionality) but you can still override the name.
You can import enum variants like regular items. For example, you can write:
use MyOption::*;
fn handle_my_option(o: MyOption) {
match o {
MyOk(foo) => {},
MyNone => {},
}
}
However, you can't have these automatically imported like the ones in the prelude (you can't add anything the prelude essentially).
If you have lots of these types, you can bundle them into a file and glob import them:
// src/my_prelude.rs
pub use crate::my_option::MyOption; // reexport the enum itself
pub use crate::my_option::MyOption::*; // reexport the individual variants
// any other things you want everywhere
// src/foo.rs
use crate::my_prelude::*;
fn foo() -> MyOption<()> {
if bar() {
MySome(()),
} else {
MyNone
}
}
Rust has a prelude module which is implicitly included in every file.
This module reexports commonly used things such as Option and its variants, but also types such as String, traits such as Clone, and functions such as drop.
Related
I have a problem where I need to create a function that takes an arbitrary type, but it needs to work differently for types that are Default vs types that are not.
I can't specialize a trait on the negative impl of Default because that feature isn't stable yet, but what I'd like is something like this:
fn my_func<T>() {
if let Some(default) = get_default::<T>() {
// Has default
} else {
// Has no default
}
}
Is this possible with the stable version of Rust?
In this case, the impls crate doesn't work (https://crates.io/crates/impls) because it will believe that T (the generic parameter) is not Default.
I need to use an attribute of the generic type of a struct in a macro.
A slightly contrived but minimal example would be if I wanted to implement a method for a generic struct, that returned the minimum value of its generic type.
struct Barn<T> {
hay: T
}
macro_rules! impl_min_hay{
($barntype:ident) => {
impl $barntype {
fn min_hay(&self) -> ????T {
????T::MIN
}
}
}
}
type SmallBarn = Barn<i8>;
type BigBarn = Barn<i64>;
impl_min_hay!(SmallBarn);
impl_min_hay!(BigBarn);
fn main() {
let barn = SmallBarn { hay: 5 };
println!("{}", barn.min_hay());
}
How would I resolve from SmallBarn to get the generic type and thus it's MIN attribute?
The actual problem I am trying to solve is a change to this macro. The macro is applied to, among others, BooleanChunked, which is defined as:
pub type BooleanChunked = ChunkedArray<BooleanType>
And I need to use an attribute of BooleanType
The only general solution I can think of is to define a trait that allows you to get at the type parameter (the syntax for this is <Type as Trait>::AssociatedType):
trait HasHayType {
type HayType;
}
impl<T> HasHayType for Barn<T> {
type HayType = T;
}
macro_rules! impl_min_hay{
($barntype:ident) => {
impl $barntype {
fn min_hay(&self) -> <$barntype as HasHayType>::HayType {
<$barntype as HasHayType>::HayType::MIN
}
}
}
}
Here's the complete program on play.rust-lang.org.
That said, once you have a trait, you don't really need the macro – you can just implement min_hay on the trait (this example makes use of the widely used num-traits crate, because this approach needs a trait for "things that have minimum values"):
use num_traits::Bounded;
trait HasHayType {
type HayType: Bounded;
fn min_hay(&self) -> Self::HayType;
}
impl<T: Bounded> HasHayType for Barn<T> {
type HayType = T;
fn min_hay(&self) -> T {
T::min_value()
}
}
And here's what that looks like as a complete program.
(And of course, once you've done that too, you don't really need the separate trait either: you can inline the definition of HasHayType into Barn, using a where clause if you want to be able to handle Barns with non-numerical hay types in addition to the ones where you'd use the macro. Presumably, though, the actual situation you have is more complex than the cut-down example you used for the question, so I gave the more complex versions in case the simplified versions wouldn't work.)
As a side note, min_hay doesn't actually need the &self parameter here; you could remove it, in order to be able to learn the minimum amount of hay without needing a barn to put it in.
I have two different structs with similar functions. Suppose that the program choose which struct to take from the user input.
I want to write something like this
fn main() {
...
let obj = if a == first {
first_object //struct First
} else {
second_object//struct Second
};
obj.read();
obj.write();
obj.some_another_method();
}
I have tried to make an enumeration
pub enum ObjectKind {
FirstObject(First),
SecondObject(Second)
}
But I cannot use methods in this case
let something = ObjectKind::FirstObject(first_object);
something.read()
//no method named `read` found for enum `structs::ObjectKind` in the current scope
//method not found in `structs::ObjectKind`
But I cannot use methods in this case
An enum is a proper type in and of itself, it's not a "union" of existing types. You can just define the methods on the enum to forward to the relevant object e.g.
impl ObjectKind {
fn read(&self) {
match self {
FirstObject(f) => f.read()
SecondObject(s) => s.read()
}
}
}
as it would probably be a bit repetitive, you can use a macro to make the forwarding easier.
Alternatively, you might be able to define a trait for the common behaviour and use a trait object to dynamically dispatch between the two, but that can be somewhat restrictive.
I realise that this is an extremely odd thing to do but I'm writing a macro I'd like to be usable in as many places as possible. Take the following code:
mod outer {
struct OuterTestStruct {}
fn do_thing() {
struct InnerTestStruct {}
mod inner {
use super::OuterTestStruct;
use super::InnerTestStruct;
}
}
}
This doesn't compile because of the use super::InnerTestStruct line. But the use super::OuterTestStruct line works fine, so my assumption here is that super skips over the fn context and goes straight to the parent mod.
Is there any way I can get a reference to InnerTestStruct from inside mod inner? Especially without knowing any context beforehand (i.e. imagine a macro invocation inside fn do_thing(), it isn't going to know it's inside a fn)
Is there any way I can get a reference to InnerTestStruct from inside mod inner?
No, super will refer to the encompassing module, not the function scope. There is no path that can name InnerTestStruct as far as I'm aware.
Since you mention macros specifically, the Rust API Guidelines warns against this exact case:
Item macros work anywhere that items are allowed
Rust allows items to be placed at the module level or within a tighter scope like a function. Item macros should work equally well as ordinary items in all of these places. The test suite should include invocations of the macro in at least the module scope and function scope.
As a simple example of how things can go wrong, this macro works great in a module scope but fails in a function scope.
macro_rules! broken {
($m:ident :: $t:ident) => {
pub struct $t;
pub mod $m {
pub use super::$t;
}
} }
broken!(m::T); // okay, expands to T and m::T
fn g() {
broken!(m::U); // fails to compile, super::U refers to the containing module not g
}
The only fix I know is to introduce another module:
mod outer {
struct OuterTestStruct {}
fn do_thing() {
mod middle { // <----------------
struct InnerTestStruct {}
mod inner {
use super::super::OuterTestStruct;
use super::InnerTestStruct;
}
}
}
}
I am currently working on a Rust port of a security tool. Inline with Rust's guides, I want to segregate the core library into its own crate, so that we can create various tools (CLI, API, streams etc.) that interface with with the core library without coupling them together.
The core library exposes two public Enums, one of them being the PermutationMode (truncated):
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum PermutationMode {
All,
Addition,
BitSquatting,
Homoglyph,
}
When creating a CLI utility using Clap, I would like to extend this library Enum as part of the CLI like so:
use clap::Clap;
use twistrs::permutate::PermutationMode;
#[derive(Clap, PartialEq, Debug)]
#[clap(name = "twistrs-cli")]
struct Opts {
#[clap(short, long)]
registered_domains: bool,
#[clap(arg_enum)]
permutation_mode: PermutationMode,
}
So that when calling the CLI, we can pass the permutation mode from the user, to the CLI, to the library seamlessly and without having the CLI needing to be aware of the internal modes (in the event that the library adds more).
./twist-cli --registered-domains --permutation_mode=all example.com
Currently this does not seem to be possible (which makes sense). One attempt was to use type aliasing:
#[derive(Clap)]
type ArgPermutationMode = PermutationMode
However we cannot use derive macros for type-aliases. I tried also "cloning" the enum and trying to map to the libraries enum:
enum ArgPermutationMode {
PermutationMode::All,
}
Which does not compile.
Question - Is it possible to extend an internal library Enum to use it as a Clap argument?
Unfortunately not. You would have to redefine the enum so that the arg_enum! macro can access the tokens.
If you add a conversion function between the two then you can make sure that upstream changes to the library enum force you to update your CLI, by giving you a compilation error:
arg_enum! {
enum ArgPermutationMode {
All,
Addition,
BitSquatting,
Homoglyph,
}
}
impl From<ArgPermutationMode> for PermutationMode {
fn from(other: ArgPermutationMode) -> PermutationMode {
match other {
ArgPermutationMode::All => PermutationMode::All,
ArgPermutationMode::Addition => PermutationMode::Addition,
ArgPermutationMode::BitSquatting => PermutationMode::BitSquatting,
ArgPermutationMode::Homoglyph => PermutationMode::Homoglyph,
}
}
}
impl From<PermutationMode> for ArgPermutationMode {
fn from(other: PermutationMode) -> ArgPermutationMode {
match other {
PermutationMode::All => ArgPermutationMode::All,
PermutationMode::Addition => ArgPermutationMode::Addition,
PermutationMode::BitSquatting => ArgPermutationMode::BitSquatting,
xPermutationMode::Homoglyph => ArgPermutationMode::Homoglyph,
}
}
}
You can reduce that boilerplate with a macro if you find yourself doing it a lot.
Given that you have control over the other crate, you could compromise by trying one of a few other options for a workaround:
Define the actual enum variants in a separate file, and use include! to use the same source in both crates. This assumes your crates are in the same workspace.
Use a macro derive like EnumIter from strum_macros. This will let you iterate over the enum's variants so you can supply them to Clap, without having a Clap dependency in that crate. You'll have a strum_macros dependency instead, so it's up to you if that is really better.
Add the clap_args! call in the internal crate, but feature-gate it. Your application crate can enable this feature, but most users wouldn't.
This is more of an extension to the above answer, incase it may help someone else. Ultimately what I ended up opting for was implementing implementing FromStr in the library as follows:
impl FromStr for PermutationMode {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_ascii_lowercase().as_str() {
"all" => Ok(PermutationMode::All),
"addition" => Ok(PermutationMode::Addition),
"bitsquatting" => Ok(PermutationMode::BitSquatting),
"homoglyph" => Ok(PermutationMode::Homoglyph),
_ => Err(),
}
}
}
To avoid having the client having to worry about the modes, we simply try to parse the string passed through the CLI into one of the permutation modes.
let permutation_mode = matches
.value_of("permutation_mode")
.unwrap()
.parse::<PermutationMode>()
.unwrap();
This way we don't need to couple the modes between the client and the library and overall makes the example CLI a lot more malleable.