doc: Add AI-generated docs

Seems ok, vive les robots!
This commit is contained in:
2025-09-09 16:19:50 +03:00
parent a71ce6d26f
commit c054a0309d
9 changed files with 277 additions and 2 deletions

View File

@@ -1,3 +1,11 @@
//! A module to load and iterate over books from a hierarchical directory structure.
//!
//! The `Loader` struct serves as the entry point for recursively traversing a directory tree,
//! parsing each file's contents into `Book` instances. `Loader` implements the `IntoIterator`
//! trait to provide a custom iterator (`LoaderIter`) capable of traversing directories and files.
//!
//! The `LoaderIter` struct manages the iteration process by maintaining a queue of directories
//! to traverse and a queue of pending `Book` objects to be returned.
use crate::application::parsers;
use crate::domain::book::Book;
use std::collections::VecDeque;

View File

@@ -1,3 +1,6 @@
//! The `Loader` struct manages an `inotify` instance that monitors a specified directory
//! for file modifications and creations. It acts as a bridge between the filesystem events
//! and the higher-level representation of books within the application.
use crate::application::parsers;
use crate::domain::book::Book;
use inotify::{Event, Inotify, WatchMask};

View File

@@ -1,4 +1,4 @@
pub mod services;
mod services;
mod loaders;
mod parsers;
mod config;

View File

@@ -7,6 +7,76 @@ use std::path::Path;
use crate::domain::author;
use crate::domain::book::Book;
/// Parses an XML file located at the given path and extracts information about books.
///
/// This function processes the XML structure using a streaming XML reader to extract details
/// about books, including:
/// - Title
/// - Language
/// - Keywords
/// - Authors (including optional details like first name, last name, middle name, and nickname)
/// - Publication year
/// - Publisher
/// - Description
///
/// # Arguments
///
/// * `path` - A reference to the file path (`&Path`) of the XML file to parse.
///
/// # Returns
///
/// Returns a `Result` where:
/// - `Ok(Vec<Book>)` contains a vector of `Book` objects constructed from the parsed XML.
/// - `Err(String)` contains an error message if the parsing fails at any stage.
///
/// # Errors
///
/// Returns an error in the following scenarios:
/// - Unable to open the file specified by `path`.
/// - Malformed XML data in the file.
/// - Issues during data extraction, such as reading incomplete or invalid values.
///
/// # Example
///
/// ```ignore
/// use std::path::Path;
/// let path = Path::new("books.xml");
/// match parse(&path) {
/// Ok(books) => {
/// for book in books {
/// println!("Book Title: {}", book.title);
/// }
/// },
/// Err(err) => eprintln!("Failed to parse XML file: {}", err),
/// }
/// ```
///
/// # XML Structure
///
/// The XML should follow a specific schema with the following relevant elements:
/// - `<book-title>`: Title of the book.
/// - `<lang>`: Language of the book.
/// - `<keywords>`: A comma-separated list of keywords/tags.
/// - `<author>`: Contains subfields `<first-name>`, `<last-name>`, `<middle-name>`, or `<nickname>`.
/// - `<year>`: Year of publication.
/// - `<publisher>`: Publisher's name.
/// - `<annotation>`: Description or annotation of the book.
///
/// # Notes
///
/// - Author data is flexible; if a nickname exists, it will override other name details.
/// - The resulting `Vec<Book>` contains just one book object, as indicated in the implementation.
///
/// # Dependencies
///
/// This function depends on the following crates:
/// - `quick-xml`: For fast XML parsing.
/// - `uuid`: To generate a unique identifier for each book.
/// - `chrono`: To serialize the current timestamp as an RFC3339 string.
///
/// # See Also
///
/// `Book` structure, which represents the parsed data for an individual book.
pub fn parse(path: &Path) -> Result<Vec<Book>, String> {
let file = File::open(path).map_err(|e| e.to_string())?;
let mut reader = Reader::from_reader(BufReader::new(file));

View File

@@ -6,6 +6,12 @@ mod rs;
mod fb2;
mod zip;
/// Error enumeration representing possible errors that can occur when parsing files.
///
/// This enumeration has the following variants:
/// - `NotSupported`: Indicates that the file format or extension is not supported.
/// - `ParseError`: Contains a `String` representing the error message when a parsing process fails.
#[derive(Debug)]
pub enum Error {
NotSupported,
@@ -21,6 +27,48 @@ impl fmt::Display for Error {
}
}
/// Parses a file at the given path and attempts to convert its contents into a vector of `Book` objects.
///
/// This function determines the file type based on its extension and delegates the parsing duties
/// to the appropriate module. Supported file extensions are:
/// - `.rs`: Processed by the `rs` module.
/// - `.fb2`: Processed by the `fb2` module.
/// - `.zip`: Processed by the `zip` module.
///
/// If the file's extension is unsupported or missing, this function returns a `NotSupported` error.
///
/// # Arguments
///
/// * `path` - A reference to a `PathBuf` that represents the file path to be parsed.
///
/// # Returns
///
/// * `Ok(Vec<Book>)` - A vector of `Book` objects if the file was successfully parsed.
/// * `Err(Error)` - An error if the file could not be parsed, the parsing process encountered
/// an issue, or the file extension is not supported.
///
/// # Errors
///
/// - `Error::ParseError` - If the file parsing fails.
/// - `Error::NotSupported` - If the file's extension is unsupported or missing.
///
/// # Examples
///
/// ```ignore
/// use std::path::PathBuf;
///
/// let path = PathBuf::from("example.rs");
/// let books = parse(&path);
/// match books {
/// Ok(book_list) => println!("Parsed {} books.", book_list.len()),
/// Err(e) => println!("Failed to parse file: {:?}", e),
/// }
/// ```
///
/// # Notes
///
/// Ensure that the appropriate parsers (`rs`, `fb2`, `zip`) are properly implemented
/// and handle all required logic for their respective file types to avoid unexpected errors.
pub fn parse(path: &PathBuf) -> Result<Vec<Book>, Error> {
match path.extension().and_then(|s| s.to_str()) {
Some("rs") => rs::parse(path).map_err(Error::ParseError),

View File

@@ -2,6 +2,44 @@ use crate::domain::author::Author;
use crate::domain::book::Book;
use std::path::PathBuf;
/// Parses a given file path into a vector containing a `Book` object.
///
/// # Arguments
///
/// * `path` - A reference to a `PathBuf` that represents the file path to be parsed.
///
/// # Returns
///
/// * `Result<Vec<Book>, String>` -
/// - On success, returns a `Vec<Book>` with a single `Book` object populated based on the input path.
/// - On failure, returns an error `String` describing the issue.
///
/// The function performs the following steps:
///
/// 1. Creates a new instance of `Book`.
/// 2. Sets the `title` of the `Book` to the string representation of the input path.
/// 3. Creates a new instance of `Author`.
/// 4. Sets the `first_name` of the `Author` to the string representation of the file extension of `path`.
/// 5. Pushes the `Author` into the `author` vector of the `Book`.
/// 6. Returns a `Vec<Book>` containing the newly created `Book`.
///
/// # Panics
///
/// The function will panic if the input path does not contain a file extension
/// (i.e., when `path.extension()` returns `None`).
///
/// # Example
///
/// ```ignore
/// use std::path::PathBuf;
///
/// let path = PathBuf::from("example.txt");
/// let books = parse(&path).unwrap();
///
/// assert_eq!(books.len(), 1);
/// assert_eq!(books[0].title, "example.txt");
/// assert_eq!(books[0].author[0].first_name, "txt");
/// ```
pub fn parse(path: &PathBuf) -> Result<Vec<Book>, String> {
let mut book = Book::new();

View File

@@ -5,6 +5,54 @@ use std::io::BufReader;
use std::path::{Path, PathBuf};
use zip::ZipArchive;
/// Parses a ZIP archive to extract a collection of `Book` objects.
///
/// This function takes a path to a ZIP archive file, reads its contents, and processes
/// each file within the archive to extract `Book` objects using a custom parser. If any
/// errors occur during file access, archive extraction, or parsing, they are returned as
/// a `String`. On success, it returns a vector of `Book` objects contained in the archive.
///
/// # Arguments
///
/// * `path` - A reference to a `Path` representing the file system path to the ZIP archive.
///
/// # Returns
///
/// * `Ok(Vec<Book>)` - A vector containing the `Book` objects successfully parsed
/// from the files in the archive.
/// * `Err(String)` - An error message if any step in opening the file, reading the archive,
/// or parsing the files fails.
///
/// # Errors
///
/// This function returns an error in the following cases:
/// * If the ZIP file cannot be opened.
/// * If the ZIP archive cannot be read.
/// * If an individual file within the archive cannot be accessed.
/// * If the parsing of a file fails.
///
/// # Example
///
/// ```ignore
/// use std::path::Path;
/// use your_crate::parse;
///
/// let path = Path::new("books_archive.zip");
/// match parse(&path) {
/// Ok(books) => {
/// for book in books {
/// println!("Parsed book: {:?}", book);
/// }
/// }
/// Err(e) => eprintln!("Failed to parse books: {}", e),
/// }
/// ```
///
/// # Dependencies
///
/// This function relies on the `ZipArchive` for working with ZIP files and a `parsers`
/// module for custom file parsing logic.
pub fn parse(path: &Path) -> Result<Vec<Book>, String> {
let file = File::open(path).map_err(|e| e.to_string())?;
let reader = BufReader::new(file);

View File

@@ -1,3 +1,63 @@
/*!
This module provides an in-memory implementation of a `Repository` for managing books, including their associated authors.
It provides mechanisms to add, update, retrieve, and filter books, along with handling relationships to authors.
# Structs
- `Book`: Internal representation of a book for the in-memory repository. It includes fields for metadata such as ID, title, author IDs, language, description, tags, publisher, and timestamps.
- `BookRepository`: The main repository struct that provides book and author management. It supports CRUD operations and filtering over books and their metadata.
# Traits
- Implements `Repository<book::Book, BookFilter>` trait to provide repository functionalities for books, such as adding, removing, updating, retrieving, and filtering.
# Implementation Details
## `Book` Struct
A lightweight representation of a `book::Book` entity used internally in the repository.
- It implements conversions for:
- **From**: Converts `book::Book` into `Book` by copying metadata and transforming author data.
- **Into**: Converts `Book` back into `book::Book`, reconstructing the related author information.
## `BookRepository` Struct
An in-memory implementation of a `Repository` that manages books and their associated authors.
- Fields:
- `books`: A vector containing all stored books in the repository.
- `authors`: A HashMap storing authors by their UUID for quick lookups.
- `author_uniques`: A mapping of unique author identifiers to their corresponding UUIDs to ensure uniqueness while managing authors.
- Methods:
- `new() -> Self`: Creates a new, empty `BookRepository`.
- `populate_authors(&self, book: &mut book::Book)`: Updates the provided book's author information with detailed metadata (e.g., names) from the repository.
- `extract_authors(&mut self, item: &mut book::Book)`: Extracts and stores unique authors from a given book into the repository.
## Repository Trait Implementation
Implements the `Repository<book::Book, BookFilter>` trait for `BookRepository` to provide standard repository features:
- `add(&mut self, mut item: book::Book)`: Adds a new book to the repository. Extracts and persists author metadata.
- Skips adding a book if a book with the same ID already exists.
- `bulk_add(&mut self, items: Vec<book::Book>)`: Adds multiple books to the repository.
- Filters out duplicate books before adding.
- `remove(&mut self, item: book::Book)`: Removes a book from the repository by its ID.
- `get(&self, id: String) -> Option<book::Book>`: Retrieves a book by its ID. Populates the book's author information if it exists.
- `update(&mut self, mut item: book::Book)`: Updates an existing book. Extracts author details and persists changes.
- `filter(&self, f: BookFilter) -> Box<dyn Iterator<Item = book::Book>>`: Filters books based on the criteria provided in the `BookFilter` struct and returns an iterator over matching books.
- Available filters:
- Title
- Description
- Language
- Tags
- Publisher
- Published date
- Last updated date
- Author (by ID or name)
# Filtering Logic
Filters books based on the provided `BookFilter` parameters:
- Matches fields like title, description, language, tags, publisher, and dates.
- Supports author-based filtering, allowing searches using either author IDs or names.
# Notes
- Author uniqueness is enforced using a mapping of unique identifiers to `Uuid` (`author_uniques` field) to manage duplicate or overlapping authors efficiently.
- Iterators are used for filtered results to allow efficient processing of the filtered data.
*/
use crate::domain::repository::{BookFilter, Repository};
use crate::domain::{author, book};
use std::collections::HashMap;

View File

@@ -2,7 +2,7 @@ use crate::application::application::Application;
pub mod domain;
mod application;
pub mod application;
pub mod infrastructure;
pub fn demo() -> Application {