Understanding rusts generics, structs, enums and more
While working on kanha, i had to write code which could be reused over and over. If you don't know what kanha is, Basically, It's a tool which provides most of the stuffs which you may want to perform while doing web-app pentesting over a particular sub(domain) via subcommands.🦄
Rust provides structs, enums, traits, functions, generics
and a lot more different mechanisms to write a simple boilerplate and reuse the code.
In this blog, I'm gonna be explaining , what they actually are and how you can get the best use of them with some examples from the Kanha
itself later.
Structs
Structs are a simple way to describe something with different characteristics. Think of it like describing a person, including details like their height, and weight.
In Rust, you can create a struct like this:
pub struct Person {
height: f32,
is_handsome: bool,
weight: i32,
}
pub fn print_struct_info() {
let pwnwriter = Person {
height: 5.7,
is_handsome: true,
weight: 55,
};
match pwnwriter.is_handsome {
true => {
println!(
"PwnWriter is {} feet tall, weighs {} Kg, and he is handsome.",
pwnwriter.height, pwnwriter.weight
);
}
false => {
println!(
"PwnWriter is {} feet tall and he is not handsome.",
pwnwriter.height
);
}
}
}
Here, we create a "Person" struct with three characteristics: height, handsomeness (a true/false value), and weight
. This allows us to store different information types for a person. We then assign these values to a variable called "pwnwriter."
Enums
Enums or enumerations
are often used when you have a finite number of options or variants for a type. Imagine you want to represent the state of a traffic signal, which can be one of three colors: red, yellow, or green
. Enums are perfect for this situation.
pub enum TrafficLight {
Red,
Yellow,
Green,
}
pub fn print_enum_info() {
let current_light = TrafficLight::Red;
match current_light {
TrafficLight::Red => println!("Stop, it's red"),
TrafficLight::Green => println!("Go, it's green"),
TrafficLight::Yellow => println!("Slow down, it's Yellow"),
};
}
Generics
Suppose you need to perform operations on variables that can have different data types. In that case, generics becomes a handy way to implement a boilerplate and reuse it over other.
pub fn print_vector<T: std::fmt::Debug>(vector: &Vec<T>) {
for item in vector {
println!("{:?}", item);
}
}
pub fn print_generics_info() {
let numbers = vec![1, 2, 3, 4, 5];
let fruits = vec!["apple", "banana", "cherry"];
println!("Numbers:");
print_vector(&numbers);
println!("Fruits:");
print_vector(&fruits);
}
In this code, print_vector
is a generic function that takes a reference to a vector of any type T
. The <T: std::fmt::Debug>
constraint ensures that the elements in the vector can be printed using println!. Inside the function, we iterate through the vector and print each item using println!.
Without using generics, you'd need to write separate functions to print vectors of different types, making longer code.
Traits
Traits define a set of methods that types can implement to provide shared behavior. They allow you to specify a contract that types must adhere to in order to implement the trait. You can then write generic code that operates on types that implement a specific trait.
pub trait Printable {
fn description(&self) -> String;
}
impl Printable for i32 {
fn description(&self) -> String {
format!("This is an integer: {}", self)
}
}
impl Printable for &'static str {
fn description(&self) -> String {
format!("This is a string: {}", self)
}
}
pub fn print_vector_with_description<T: Printable>(vector: &Vec<T>) {
for item in vector {
println!("{}", item.description());
}
}
pub fn print_generics_info_with_trait() {
let numbers = vec![1, 2, 3, 4, 5];
let fruits = vec!["apple", "banana", "cherry"];
println!("Numbers:");
print_vector_with_description(&numbers);
println!("Fruits:");
print_vector_with_description(&fruits);
}
This code defines a Printable
trait with a description
method. It implements this trait for i32
and &'static str
types, providing descriptions. The print_vector_with_description
function accepts a vector of any type that implements Printable
and prints their descriptions. Finally, print_generics_info_with_trait
uses this function to print descriptions of numbers and fruits in vectors.
The below is an example trait, i used in kanha
to fetch status codes of urls taking different Args
.
pub trait ArgsWithTasks {
fn tasks(&self) -> usize;
}
impl ArgsWithTasks for StatusArgs {
fn tasks(&self) -> usize {
self.tasks
}
}
Modules
Modules allows as to group together our code inside a block. A module skeleton should like this.
pub mod foo {
struct bar {}
pub fn bar() {}
// and soo on ...
}
The below is an example on, how i use modules in my projects.
pub mod kanha_helpers {
use crate::log::abort;
use std::fs::File;
use std::io::{self, BufRead};
/// https://doc.rust-lang.org/rust-by-example/std_misc/rile/read_lines.html
/// Reads a file line by line and returns an iterator for reading those lines, or aborts with a message if the file doesn't exist.
pub async fn read_lines(filename: &str) -> io::Result<io::Lines<io::BufReader<File>>> {
match File::open(filename) {
Ok(file) => Ok(io::BufReader::new(file).lines()),
Err(_) => {
abort("No such file in this location");
}
}
}
/// https://www.youtube.com/watch?v=K_wnB9ibCMg&t=1078s
/// Reads lines from the standard input, collects them into a Vec<String> using the collect method, and returns the result
pub fn read_urls_from_stdin() -> Result<Vec<String>, Box<dyn std::error::Error>> {
let stdin = io::stdin();
let urls: Result<Vec<String>, io::Error> = stdin.lock().lines().collect();
urls.map_err(|err| err.into())
}
}
To use any function,trait,enums or other
from the module
. We need to call them like this.
use crate::commands::kanha_helpers::read_lines;
pub async fn fuzz_url(fuzzer_args: FuzzerArgs) -> Result<(), Box<dyn std::error::Error>> {
let lines = read_lines(&fuzzer_args.wordlist).await?;
Ok(())
}
Ig, that's all pretty much about it. For more, i suggest to check source code of kanha where i tried my best to make my code as clean as possible. Show some love and give it a star.
Have any suggestions on my code
,?  create an issue or a pull request 💫