2

with some help, i was able to traverse directory and parse it into Collection struct recursively like this

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Collection {
    pub relative_path: String,
    pub name: String,
    pub collections: Vec<Collection>,
    pub requests: Vec<Request>,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Request {
    pub relative_path: String,
    pub name: String,
}

fn build_collection_from_path<P: AsRef<Path>>(path: P) -> Collection {
    let path = path.as_ref();
    let name = path.file_name().unwrap().to_string_lossy().into_owned();
    let relative_path = path.to_string_lossy().into_owned();

    let mut collection = Collection {
        relative_path: relative_path.clone(),
        name,
        collections: vec![],
        requests: vec![],
    };

    if let Ok(entries) = fs::read_dir(path) {
        for entry in entries {
            if let Ok(entry) = entry {
                let entry_path = entry.path();
                if entry_path.is_dir() {
                    // It's a folder, add as a sub-collection
                    collection
                        .collections
                        .push(build_collection_from_path(entry_path));
                } else if entry_path.is_file() {
                    // It's a file, add as a request
                    let file_name = entry_path
                        .file_name()
                        .unwrap()
                        .to_string_lossy()
                        .into_owned();
                    let file_relative_path = entry_path.to_string_lossy().into_owned();
                    collection.requests.push(Request {
                        relative_path: file_relative_path,
                        name: file_name,
                    });
                }
            }
        }
    }

    collection
}

// Function to traverse both root folders (collections) and root-level files (requests)
fn bfs_traverse_folders_and_files<P: AsRef<Path>>(root_path: P) -> (Vec<Collection>, Vec<Request>) {
    let root_path = root_path.as_ref();

    // Initialize the root collections and requests
    let mut root_collections: Vec<Collection> = Vec::new();
    let mut root_requests: Vec<Request> = Vec::new();

    // Traverse the root directory
    if let Ok(entries) = fs::read_dir(root_path) {
        for entry in entries {
            if let Ok(entry) = entry {
                let entry_path = entry.path();
                if entry_path.is_dir() {
                    // Create and push the folder as a collection
                    let collection = build_collection_from_path(entry_path);
                    root_collections.push(collection);
                } else if entry_path.is_file() {
                    // Push the file as a request
                    let file_name = entry_path
                        .file_name()
                        .unwrap()
                        .to_string_lossy()
                        .into_owned();
                    let file_relative_path = entry_path.to_string_lossy().into_owned();
                    root_requests.push(Request {
                        relative_path: file_relative_path,
                        name: file_name,
                    });
                }
            }
        }
    }

    (root_collections, root_requests)
}


    let (root_collections_recursive, root_requests_recursive) =
        bfs_traverse_folders_and_files(root_path);

    println!(
        "Root Collections Recursive:\n{:#?}",
        root_collections_recursive
    );
    println!("Root Requests Recursive:\n{:#?}", root_requests_recursive);

but i'm unable to do this iteratively and assign collections properly

for iterative approach i was thinking of using a stack vector and then keeping a mutable ref to the collection but i can't get it to compile because i cannot seem to share a mutable reference

if i slap a .clone() to it then it doesn't translate to the struct properly because i copied over the contents early? is there a way to get around it please help.

Edit:

i was able to do this iteratively but i had to use unsafe in order to mutate the parent collection, not sure if it could be done in a better way. i'll look into RefCell as well as suggested by @cafce25

here's the code

// Function to iteratively build the Collection structure
fn build_collection_from_path_iterative<P: AsRef<Path>>(root_path: P) -> Collection {
    let root_path = root_path.as_ref();
    let root_name = root_path
        .file_name()
        .unwrap()
        .to_string_lossy()
        .into_owned();
    let root_relative_path = root_path.to_string_lossy().into_owned();

    let mut root_collection = Collection {
        relative_path: root_relative_path.clone(),
        name: root_name,
        collections: vec![],
        requests: vec![],
    };

    // Stack to simulate DFS, storing (current path, pointer to parent collection)
    let mut stack: Vec<(PathBuf, *mut Collection)> = Vec::new();
    stack.push((
        root_path.to_path_buf(),
        &mut root_collection as *mut Collection,
    ));

    while let Some((current_path, parent_collection_ptr)) = stack.pop() {
        if let Ok(entries) = fs::read_dir(&current_path) {
            for entry in entries {
                if let Ok(entry) = entry {
                    let entry_path = entry.path();
                    let parent_collection = unsafe { &mut *parent_collection_ptr }; // Dereference the raw pointer to modify parent

                    if entry_path.is_dir() {
                        // Create sub-collection for directory
                        let sub_collection_name = entry_path
                            .file_name()
                            .unwrap()
                            .to_string_lossy()
                            .into_owned();
                        let sub_collection = Collection {
                            relative_path: entry_path.to_string_lossy().into_owned(),
                            name: sub_collection_name,
                            collections: vec![],
                            requests: vec![],
                        };

                        // Push the sub-collection into the parent collection's `collections` vector
                        parent_collection.collections.push(sub_collection);

                        // Push the new sub-collection onto the stack for further traversal
                        let sub_collection_ptr =
                            parent_collection.collections.last_mut().unwrap() as *mut Collection; // Get a pointer to the last added collection
                        stack.push((entry_path.clone(), sub_collection_ptr));
                    } else if entry_path.is_file() {
                        // Add file as a request
                        let file_name = entry_path
                            .file_name()
                            .unwrap()
                            .to_string_lossy()
                            .into_owned();
                        let file_relative_path = entry_path.to_string_lossy().into_owned();
                        parent_collection.requests.push(Request {
                            relative_path: file_relative_path,
                            name: file_name,
                        });
                    }
                }
            }
        }
    }

    root_collection
}
3
  • 2
    "i cannot seem to share a mutable reference" yes, that's why they are often called exclusive references, and that's a more accurate description. You probably want to use a RefCell Commented Sep 20, 2024 at 5:23
  • 2
    I'm confused by your description why would an iterative BFS need to share anything? In a loop you pop a path from the stack, push files to the results, and push new dir entries back on the stack, what sharing is there? Commented Sep 20, 2024 at 8:13
  • @Masklinn i need to update the parent collection that's why i need to share the reference and update it. i've updated my post, i was able to do it iteratively but i had to use unsafe Commented Sep 20, 2024 at 14:52

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.