Rust examples: Difference between revisions
Jump to navigation
Jump to search
Created page with "=Introduction= The reason for this page is because MediaWiki gets a bit testy with over 1000 lines grrhhhhh so bits of the rust page are on here =Date Handling in Rust Found the on twitter (not all bad) @orhanbalci Type conversion and dates are the worst in most languages so thought I would keep this. <syntaxhighlight lang="rs"> fn main() { // you can use chrono crate for date time operations. // chrono crate is more capable than standard library std::time modul..." |
No edit summary |
||
Line 88: | Line 88: | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=Type State Pattern= | |||
In some cases we only want to be able to do some functions on a struct based on the state of the struct. In rust we could create a field in the struct called state and maintain which functions are allowed based on the current state. However rust provides a better approach referred to as the '''type state pattern'''. For example if we wanted make a password manager structure we could do this. | |||
<syntaxhighlight lang="rs"> | |||
#![allow(unused)] | |||
use std::collections::HashMap; | |||
use std::marker::PhantomData; | |||
struct Locked; | |||
struct Unlocked; | |||
// PasswordManager<Locked> != PasswordManager<Unlocked> | |||
struct PasswordManager<State = Locked> { | |||
master_pass: String, | |||
passwords: HashMap<String, String>, | |||
state: PhantomData<State>, | |||
} | |||
// Locked Functions | |||
impl PasswordManager<Locked> { | |||
pub fn unlock(self, master_pass: String) -> PasswordManager<Unlocked> { | |||
PasswordManager { | |||
master_pass: self.master_pass, | |||
passwords: self.passwords, | |||
state: PhantomData, | |||
} | |||
} | |||
} | |||
// Unlocked Functions | |||
impl PasswordManager<Unlocked> { | |||
pub fn lock(self) -> PasswordManager<Locked> { | |||
PasswordManager { | |||
master_pass: self.master_pass, | |||
passwords: self.passwords, | |||
state: PhantomData, | |||
} | |||
} | |||
pub fn list_passwords(&self) -> &HashMap<String, String> { | |||
&self.passwords | |||
} | |||
pub fn add_password(&mut self, username: String, password: String) { | |||
self.passwords.insert(username, password); | |||
} | |||
} | |||
// Generic Functions | |||
impl<State> PasswordManager<State> { | |||
pub fn encryption(&self) -> String { | |||
todo!() | |||
} | |||
pub fn version(&self) -> String { | |||
todo!() | |||
} | |||
} | |||
// Constructor | |||
impl PasswordManager { | |||
pub fn new(master_pass: String) -> Self { | |||
PasswordManager { | |||
master_pass, | |||
passwords: Default::default(), | |||
state: PhantomData, | |||
} | |||
} | |||
} | |||
fn main() { | |||
let mut manager = PasswordManager::new("password123".to_owned()); | |||
let manager = manager.unlock("password123".to_owned()); | |||
manager.list_passwords(); | |||
manager.lock(); | |||
} | |||
</syntaxhighlight> | |||
The benefits to doing this are | |||
*Only functions allowed are displayed in the IDE. E.g. a locked password manager cannot see the functions for an unlocked password manager | |||
*The state PhantomData<State> is compiled out and reduces memory footprint |
Revision as of 01:49, 10 October 2024
Introduction
The reason for this page is because MediaWiki gets a bit testy with over 1000 lines grrhhhhh so bits of the rust page are on here =Date Handling in Rust Found the on twitter (not all bad) @orhanbalci Type conversion and dates are the worst in most languages so thought I would keep this.
fn main() {
// you can use chrono crate for date time operations.
// chrono crate is more capable than standard library std::time module
use chrono::prelude::*;
use chrono::Duration;
// you can retrieve current date in Utc timezone as follows
let current_date = Utc::today();
println!("Utc current date: {}", current_date);
// you can retrieve current date in local timezone as follows
let local_current_date = Local::today();
println!("Local current date: {}", local_current_date);
// you can retrieve current time in UTC as follows
let current_time_utc = Utc::now();
println!( "Utc current time: {}", current_time_utc);
// you can retrieve current time in local time zone as follows
let current_time_local = Local::now();
println!("Local current time: {}", current_time_local);
// you can add some duration to a chrono::Date
// succ method gets succeeding date
let today = Utc::today();
let tomorrow = today + Duration::days(1);
assert_eq!(today.succ(), tomorrow);
// you can subtract some duration from a chrono
// pred method gets previous date
let today = Utc::today();
let yesterday = today - Duration::days(1);
assert_eq!(today.pred(), yesterday);
// you can get UNIX timestamp (epoch) value for a datetime using
// timestamp method of chrono::offset::TimeZone trait.
// since timestamps have numeric representation, they are easy to store in db
// and send through network. You can aldo prefer this notation in your APIs
let dt = Utc.ymd(1970, 1, 1).and_hms_milli(0, 0, 1, 0);
assert_eq!(dt.timestamp(), 1);
//you can also get timestamp value of a datetime in milliseconds
let dt = Utc.ymd(1970, 1, 1).and_hms_milli(0, 0, 1, 500);
assert_eq!(dt.timestamp_millis(), 1500);
//you can convert create a chrono::DateTime from a timestamp seconds
let timestamp = 15;
let datetime = Utc.timestamp(timestamp, 0);
assert_eq!(datetime.timestamp(), 15);
//you can get difference of two date times as follows
let first = Utc.ymd(1970, 1, 1).and_hms_milli(0, 0, 1, 0);
let second = Utc.ymd(1970, 1, 1).and_hms_milli(0, 0, 2, 0);
let difference: Duration = second.signed_duration_since(first);
assert_eq!(difference, Duration::seconds(1));
// you can also add and subtract duration from a DateTime struct
let now = Utc::now();
let yesterday_at_the_same_time = now - Duration::days(1);
println!("Yesterday at the same time: {}", yesterday_at_the_same_time);
//you can compare durations
assert_eq! (Duration::days(1), Duration::hours(24));
//you can format your DateTime struct using strftime formatting options
let now = Utc::now();
println!("{}", now. format( "%d.%m.%Y %H:%M"));
//you can parse DateTime from a formatted string as below
let some_time = NaiveDateTime::parse_from_str("01.10.2021 14:21", "%d.%m.%Y %H:%M").unwrap( );
assert_eq!(some_time, NaiveDate::from_ymd(2021,10,1).and_hms(14,21,0));
}
Type State Pattern
In some cases we only want to be able to do some functions on a struct based on the state of the struct. In rust we could create a field in the struct called state and maintain which functions are allowed based on the current state. However rust provides a better approach referred to as the type state pattern. For example if we wanted make a password manager structure we could do this.
#![allow(unused)]
use std::collections::HashMap;
use std::marker::PhantomData;
struct Locked;
struct Unlocked;
// PasswordManager<Locked> != PasswordManager<Unlocked>
struct PasswordManager<State = Locked> {
master_pass: String,
passwords: HashMap<String, String>,
state: PhantomData<State>,
}
// Locked Functions
impl PasswordManager<Locked> {
pub fn unlock(self, master_pass: String) -> PasswordManager<Unlocked> {
PasswordManager {
master_pass: self.master_pass,
passwords: self.passwords,
state: PhantomData,
}
}
}
// Unlocked Functions
impl PasswordManager<Unlocked> {
pub fn lock(self) -> PasswordManager<Locked> {
PasswordManager {
master_pass: self.master_pass,
passwords: self.passwords,
state: PhantomData,
}
}
pub fn list_passwords(&self) -> &HashMap<String, String> {
&self.passwords
}
pub fn add_password(&mut self, username: String, password: String) {
self.passwords.insert(username, password);
}
}
// Generic Functions
impl<State> PasswordManager<State> {
pub fn encryption(&self) -> String {
todo!()
}
pub fn version(&self) -> String {
todo!()
}
}
// Constructor
impl PasswordManager {
pub fn new(master_pass: String) -> Self {
PasswordManager {
master_pass,
passwords: Default::default(),
state: PhantomData,
}
}
}
fn main() {
let mut manager = PasswordManager::new("password123".to_owned());
let manager = manager.unlock("password123".to_owned());
manager.list_passwords();
manager.lock();
}
The benefits to doing this are
- Only functions allowed are displayed in the IDE. E.g. a locked password manager cannot see the functions for an unlocked password manager
- The state PhantomData<State> is compiled out and reduces memory footprint