Coding Guidelines
TODO: Add some basic rust ones
https://doc.rust-lang.org/nightly/style-guide/
fmt & clippy
Before checking in a PR, please make sure to run cargo fmt
and cargo clippy
. This will format your code and check for errors.
cargo fmt
cargo clippy --fix --allow-dirty
Try to avoid .clone() if possible
Pass values by reference or by value instead of cloning them unless absolutely necessary. Cloning can be expensive, especially for large structs or strings.
Use PathBuf and Path over String and str
When referencing file system paths, use Path and PathBuf over String and &str. This is because PathBuf is a struct that represents a path and is more powerful than a raw string. For example, it makes sure the paths are cross platform (windows and unix) and allows you to check if a path is a file or directory. PathBuf also has other useful methods to get the file name, directory name, components, etc.
Use impl AsRef
where possible
As function parameters, instead of taking in a &Path
, &str
, PathBuf
or String
take in a impl AsRef<Path>
or impl AsRef<str>
. This way the consumer can decide whether or not they want the value to be borrowed or passed in by reference, and does not have to make sure the value is a reference.
This makes it much is easier and more flexible for external consumers.
TODO: Examples of signatures and external consumers
#![allow(unused)] fn main() { pub fn load_path(repo: &LocalRepository, path: impl AsRef<Path>) -> Result<MerkleTreeNode> }
vs
#![allow(unused)] fn main() { pub fn load_path(repo: &LocalRepository, path: PathBuf) -> Result<MerkleTreeNode> }
vs
#![allow(unused)] fn main() { pub fn load_path(repo: &LocalRepository, path: &Path) -> Result<MerkleTreeNode> }
Use util::fs functions over std::fs
The util::fs functions handle errors a little more gracefully and have additional functionality for reading and writing to the file system cross platform. For example std::fs::remove_file
does not tell you which file could not be removed and will give you an error like this:
Os { code: 2, kind: NotFound, message: "No such file or directory" }
util::fs::remove_file
will add the file name to the error message so you can see which file could not be removed.
Be cognizant of loading too much of the Merkle Tree
The CommitMerkleTree
struct lets you load subsets of the merkle tree and skip directly to dir nodes. It also has functionality to only load 1 or 2 levels deep (avoiding deep recursion).
Make sure you are only loading what you need to get the information you need to return.
For example, if you just need the size of a directory, you don't need to load it's children.
#![allow(unused)] fn main() { let load_recursive = false; let node = CommitMerkleTree::from_path(repo, commit, path, load_recursive)?; }
If you need all the files in a directory, and you don't want all the levels below it, you can specify the depth to load.
#![allow(unused)] fn main() { // This will load the VNodes and the FileNode/DirNode children of the VNodes let node = CommitMerkleTree::read_depth(repo, hash, 2)?; }