Skip to content

Commit

Permalink
proto
Browse files Browse the repository at this point in the history
  • Loading branch information
solidiquis committed Apr 28, 2022
0 parents commit 6e10f26
Show file tree
Hide file tree
Showing 10 changed files with 262 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/target
.DS_Store
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "erdtree"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
1 change: 1 addition & 0 deletions assets/a.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
a
1 change: 1 addition & 0 deletions assets/b.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ab
Empty file added assets/c/a.txt
Empty file.
5 changes: 5 additions & 0 deletions src/file_tree/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
use std::io;

pub fn not_dir_err() -> io::Error {
io::Error::new(io::ErrorKind::InvalidInput, "Argument 'root_location' must be a path to a directory.")
}
111 changes: 111 additions & 0 deletions src/file_tree/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#![allow(dead_code)]

mod error;
mod tree_node;

use std::path::Path;
use std::fs;
use std::io;
use tree_node::{TreeNode, FileType};

pub type FileTreeResult<'a> = Result<FileTree<'a>, io::Error>;

pub struct FileTree<'a> {
root_location: &'a Path,
root_node: TreeNode
}

impl<'a> FileTree<'a> {
pub fn new<S>(root_location: &'a S) -> FileTreeResult<'a>
where S: AsRef<Path> + ?Sized
{
let root_md = fs::metadata(root_location)?;

if !root_md.is_dir() {
return Err(error::not_dir_err())
}

let root_node = TreeNode::new(
root_location,
FileType::Dir,
".".to_string(),
0
);

Ok(Self {
root_location: root_location.as_ref(),
root_node
})
}

pub fn get_root_node(&self) -> &TreeNode {
&self.root_node
}

pub fn len(&self) -> u64 {
self.root_node.get_metadata().len()
}

pub fn display(&self) {
let root_node = self.get_root_node();
let buffer = "".to_string();
let result = Self::sprintf_output(&root_node, buffer);

println!("{}", result);
}

fn sprintf_output(node: &TreeNode, mut buffer: String) -> String {
buffer.push_str(&Self::sprintf_row(&node));
buffer.push_str("\n");

for child in node.iter_children() {
if child.is_dir() {
buffer = Self::sprintf_output(child, buffer);
} else {
buffer.push_str(&Self::sprintf_row(&child));
buffer.push_str("\n");
}
}

buffer
}

fn sprintf_row(node: &TreeNode) -> String {
let mut prefix = "".to_string();

for _ in 0..node.get_generation() {
prefix.push_str("\t")
}

format!("{}{} {}", prefix, node.get_file_name(), node.len())
}
}

#[cfg(test)]
mod test {
#[test]
fn test_file_tree() {
use super::FileTree;
use super::tree_node::FileType;

let file_tree = FileTree::new("./assets/").unwrap();
let root_node = file_tree.get_root_node();

assert_eq!(root_node.get_generation(), 0);
assert_eq!(root_node.num_children(), 3);

let first_gen_child = root_node.iter_children().nth(0).unwrap();

assert_eq!(first_gen_child.get_generation(), 1);

let second_gen_child = root_node
.iter_children()
.find(|child| child.get_file_type() == &FileType::Dir)
.unwrap()
.iter_children()
.nth(0)
.unwrap();

assert_eq!(second_gen_child.get_generation(), 2);
}
}
119 changes: 119 additions & 0 deletions src/file_tree/tree_node.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
use std::fs;
use std::io;
use std::path::{PathBuf, Path};
use std::slice::Iter;

pub type TreeNodeResult = Result<TreeNode, io::Error>;
pub type Children = Vec<TreeNode>;

pub struct TreeNode {
location: PathBuf,
file_type: FileType,
file_name: String,
metadata: fs::Metadata,
generation: u64,
children: Children
}

#[derive(PartialEq)]
pub enum FileType {
File,
Dir,
Symlink,
}

impl TreeNode {
pub fn new<S>(location: &S, file_type: FileType, file_name: String, generation: u64) -> Self
where S: AsRef<Path> + ?Sized
{
let metadata = fs::metadata(location).unwrap();

let mut node = Self {
location: location.as_ref().to_path_buf(),
file_type,
file_name,
metadata,
generation,
children: vec![]
};

node.construct_branches(generation).unwrap();

node
}

pub fn get_location(&self) -> &Path {
&self.location
}

pub fn get_metadata(&self) -> &fs::Metadata {
&self.metadata
}

pub fn is_dir(&self) -> bool {
self.file_type == FileType::Dir
}

pub fn is_not_dir(&self) -> bool {
!self.is_dir()
}

pub fn get_file_type(&self) -> &FileType {
&self.file_type
}

pub fn get_file_name(&self) -> &str {
&self.file_name
}

pub fn get_generation(&self) -> u64 {
self.generation
}

pub fn add_child(&mut self, child: Self) {
self.children.push(child);
}

pub fn iter_children(&self) -> Iter<'_, TreeNode> {
self.children.iter()
}

pub fn num_children(&self) -> u64 {
self.children.len() as u64
}

pub fn len(&self) -> u64 {
self.metadata.len()
}

fn ascertain_file_type(entry: &fs::DirEntry) -> io::Result<FileType> {
let file_type = entry.file_type()?;

if file_type.is_dir() { return Ok(FileType::Dir) }
if file_type.is_file() { return Ok(FileType::File) }

Ok(FileType::Symlink)
}

fn construct_branches(&mut self, generation: u64) -> Result<(), io::Error> {
if self.is_not_dir() { return Ok(()) }

for possible_entry in fs::read_dir(self.get_location())? {
if let Err(_) = possible_entry { continue }

let entry = possible_entry.unwrap();
let epath = entry.path();
let fname = entry.file_name().into_string().unwrap();
let ftype = match Self::ascertain_file_type(&entry) {
Ok(file_type) => file_type,
_ => continue
};

let new_node = Self::new(&epath, ftype, fname, generation + 1);

self.add_child(new_node);
}

Ok(())
}
}
8 changes: 8 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
mod file_tree;

use file_tree::FileTree;

fn main() {
let file_tree = FileTree::new("./assets/").unwrap();
file_tree.display();
}

0 comments on commit 6e10f26

Please sign in to comment.