Created
August 12, 2020 12:29
-
-
Save MartinKavik/678ad94e8a71dcea439c10a9f63387d9 to your computer and use it in GitHub Desktop.
Seed `view` optimization by tracking data changes in `view` functions arguments
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![allow(dead_code)] | |
use std::collections::BTreeMap; | |
use std::collections::hash_map::DefaultHasher; | |
use std::hash::{Hash, Hasher}; | |
struct Model { | |
todos: BTreeMap<String, Todo>, | |
new_todo_title: String, | |
selected_todo: Option<SelectedTodo>, | |
filter: Filter, | |
} | |
struct Todo { | |
title: String, | |
completed: bool, | |
} | |
struct SelectedTodo { | |
title: String, | |
} | |
enum Filter { | |
All, | |
Active, | |
} | |
fn main() { | |
let mut view_arg_1_hash: Option<u64> = None; | |
let mut view_new_todo_title_arg_1_hash: Option<u64> = None; | |
let mut model = Model { | |
todos: BTreeMap::new(), | |
new_todo_title: "my todo".to_owned(), | |
selected_todo: None, | |
filter: Filter::All, | |
}; | |
println!("--- 1. view call ---"); | |
view(&model, &mut view_arg_1_hash, &mut view_new_todo_title_arg_1_hash); | |
println!("--- 2. view call --- "); | |
view(&model, &mut view_arg_1_hash, &mut view_new_todo_title_arg_1_hash); | |
println!("--- 3. view call --- "); | |
// change `Model` a bit to trigger at least root `view` logic | |
model.filter = Filter::Active; | |
view(&model, &mut view_arg_1_hash, &mut view_new_todo_title_arg_1_hash); | |
println!("--- 4. view call --- "); | |
// change `new_todo_title` to trigger root `view` logic and also `view_new_todo_title` logic | |
model.new_todo_title = "change my todo title".to_owned(); | |
view(&model, &mut view_arg_1_hash, &mut view_new_todo_title_arg_1_hash); | |
} | |
// Arguments `view_arg_1_hash` and `view_new_todo_title_arg_1_hash` + hashing + match | |
// should be refactored and then hidden by the attribute `#[view]` | |
fn view(model: &Model, view_arg_1_hash: &mut Option<u64>, view_new_todo_title_arg_1_hash: &mut Option<u64>) { | |
let hash = as_bytes_and_calculate_hash(model); | |
let old_hash = view_arg_1_hash.replace(hash); | |
match old_hash { | |
Some(old_hash) if hash == old_hash => return, | |
_ => () | |
} | |
println!("view called"); | |
view_new_todo_title(&model.new_todo_title, view_new_todo_title_arg_1_hash); | |
} | |
fn view_new_todo_title(title: &str, view_new_todo_title_arg_1_hash: &mut Option<u64>) { | |
// Note: `to_owned` is needed because of `::std::mem::size_of::<T>(),` in `any_as_u8_slice` | |
// but there is probably a way how to get bytes from reference to unsized types. | |
let hash = as_bytes_and_calculate_hash(&title.to_owned()); | |
let old_hash = view_new_todo_title_arg_1_hash.replace(hash); | |
match old_hash { | |
Some(old_hash) if hash == old_hash => return, | |
_ => () | |
} | |
println!("view new todo title called"); | |
} | |
fn calculate_hash<T: Hash + ?Sized>(t: &T) -> u64 { | |
let mut s = DefaultHasher::new(); | |
t.hash(&mut s); | |
s.finish() | |
} | |
fn as_bytes_and_calculate_hash<T>(t: &T) -> u64 { | |
let bytes: &[u8] = unsafe { any_as_u8_slice(t) }; | |
calculate_hash(bytes) | |
} | |
unsafe fn any_as_u8_slice<T: Sized>(p: &T) -> &[u8] { | |
::std::slice::from_raw_parts( | |
(p as *const T) as *const u8, | |
::std::mem::size_of::<T>(), | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
It can be run in https://play.rust-lang.org/