docs: Add rustdoc for filter_plugin, binary_detection, and lib.rs
Co-authored-by: aider (openai/andrew/openrouter/sonoma-sky-alpha) <aider@aider.chat>
This commit is contained in:
15
PLAN.md
15
PLAN.md
@@ -50,21 +50,6 @@ Private helpers (e.g., internal `fn` without `pub`) are not flagged, as they don
|
|||||||
- Impl `MetaPlugin` methods (`is_finalized`, `set_finalized`, `finalize`, `update`, `meta_type`, `outputs`, etc.): No docs.
|
- Impl `MetaPlugin` methods (`is_finalized`, `set_finalized`, `finalize`, `update`, `meta_type`, `outputs`, etc.): No docs.
|
||||||
- Overall: Lacks docs for the public trait impl.
|
- Overall: Lacks docs for the public trait impl.
|
||||||
|
|
||||||
4. **src/filter_plugin/head.rs** [DONE]
|
|
||||||
- `HeadBytesFilter` and `HeadLinesFilter` structs: No docs.
|
|
||||||
- `new()` functions: Partial.
|
|
||||||
- Impl `FilterPlugin` methods (`filter`, `clone_box`, `options`): No docs.
|
|
||||||
- Overall: No rustdoc at all for public impl.
|
|
||||||
|
|
||||||
5. **src/common/binary_detection.rs** [DONE]
|
|
||||||
- `check_binary_content_allowed()` function: Partial (missing examples).
|
|
||||||
- `is_content_binary()` function: Partial.
|
|
||||||
- Overall: Functions lack full error handling docs.
|
|
||||||
|
|
||||||
6. **src/lib.rs** [DONE]
|
|
||||||
- Module re-exports and `init_plugins()` function: No docs.
|
|
||||||
- Overall: Library-level docs are minimal.
|
|
||||||
|
|
||||||
7. **src/services/filter_service.rs** [DONE]
|
7. **src/services/filter_service.rs** [DONE]
|
||||||
- `FilterService` struct: Partial doc.
|
- `FilterService` struct: Partial doc.
|
||||||
- `new()`, `create_filter_chain()`, `filter_data()`, `process_with_filter()` methods: Partial or missing.
|
- `new()`, `create_filter_chain()`, `filter_data()`, `process_with_filter()` methods: Partial or missing.
|
||||||
|
|||||||
@@ -17,6 +17,39 @@ use std::collections::HashMap;
|
|||||||
/// * `Result<(), StatusCode>` -
|
/// * `Result<(), StatusCode>` -
|
||||||
/// * `Ok(())` if binary content is allowed or content is not binary
|
/// * `Ok(())` if binary content is allowed or content is not binary
|
||||||
/// * `Err(StatusCode::BAD_REQUEST)` if binary content is not allowed and content is binary
|
/// * `Err(StatusCode::BAD_REQUEST)` if binary content is not allowed and content is binary
|
||||||
|
/// Check if content is binary when allow_binary is false
|
||||||
|
///
|
||||||
|
/// Validates whether binary content is permitted for the item. If not allowed and content
|
||||||
|
/// is detected as binary, returns a bad request status. Uses metadata or streams content
|
||||||
|
/// for detection if needed.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `item_service` - Reference to the async item service for content access.
|
||||||
|
/// * `item_id` - The ID of the item to check.
|
||||||
|
/// * `metadata` - Metadata associated with the item (checked for "text" key).
|
||||||
|
/// * `allow_binary` - Whether binary content is allowed (bypasses check if true).
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// * `Result<(), StatusCode>` -
|
||||||
|
/// * `Ok(())` if binary content is allowed or content is not binary.
|
||||||
|
/// * `Err(StatusCode::BAD_REQUEST)` if binary content is not allowed and content is binary.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Propagates `StatusCode` for validation failures.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// // If allow_binary = false and content is text
|
||||||
|
/// check_binary_content_allowed(&service, 1, &metadata, false)?;
|
||||||
|
/// // Succeeds
|
||||||
|
///
|
||||||
|
/// // If allow_binary = false and content is binary
|
||||||
|
/// // Returns Err(StatusCode::BAD_REQUEST)
|
||||||
|
/// ```
|
||||||
pub async fn check_binary_content_allowed(
|
pub async fn check_binary_content_allowed(
|
||||||
item_service: &AsyncItemService,
|
item_service: &AsyncItemService,
|
||||||
item_id: i64,
|
item_id: i64,
|
||||||
@@ -46,6 +79,34 @@ pub async fn check_binary_content_allowed(
|
|||||||
/// * `Ok(true)` if content is binary
|
/// * `Ok(true)` if content is binary
|
||||||
/// * `Ok(false)` if content is text
|
/// * `Ok(false)` if content is text
|
||||||
/// * `Err(StatusCode)` if an error occurs during checking
|
/// * `Err(StatusCode)` if an error occurs during checking
|
||||||
|
/// Helper function to determine if content is binary
|
||||||
|
///
|
||||||
|
/// Checks existing "text" metadata first; if absent or unset, streams and analyzes
|
||||||
|
/// the content to detect binary nature. Logs warnings on detection failures.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `item_service` - Reference to the async item service for content access.
|
||||||
|
/// * `item_id` - The ID of the item to check.
|
||||||
|
/// * `metadata` - Metadata associated with the item (checked for "text" key).
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// * `Result<bool, StatusCode>` -
|
||||||
|
/// * `Ok(true)` if content is binary.
|
||||||
|
/// * `Ok(false)` if content is text.
|
||||||
|
/// * `Err(StatusCode)` if an error occurs during checking (e.g., INTERNAL_SERVER_ERROR).
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// * `StatusCode::INTERNAL_SERVER_ERROR` if content access fails.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let is_bin = is_content_binary(&service, 1, &metadata).await?;
|
||||||
|
/// assert!(is_bin == false); // For text content
|
||||||
|
/// ```
|
||||||
pub async fn is_content_binary(
|
pub async fn is_content_binary(
|
||||||
item_service: &AsyncItemService,
|
item_service: &AsyncItemService,
|
||||||
item_id: i64,
|
item_id: i64,
|
||||||
|
|||||||
@@ -4,20 +4,43 @@ use crate::common::PIPESIZE;
|
|||||||
use crate::services::filter_service::register_filter_plugin;
|
use crate::services::filter_service::register_filter_plugin;
|
||||||
|
|
||||||
/// A filter that reads the first N bytes from the input stream.
|
/// A filter that reads the first N bytes from the input stream.
|
||||||
|
/// A filter that reads the first N bytes from the input stream.
|
||||||
|
///
|
||||||
|
/// Limits the output to the initial bytes specified in the configuration.
|
||||||
|
/// Useful for previewing file contents without reading everything.
|
||||||
|
///
|
||||||
|
/// # Fields
|
||||||
|
///
|
||||||
|
/// * `remaining` - Number of bytes left to read before stopping.
|
||||||
pub struct HeadBytesFilter {
|
pub struct HeadBytesFilter {
|
||||||
remaining: usize,
|
remaining: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A filter that reads the first N bytes from the input stream.
|
||||||
|
///
|
||||||
|
/// Limits the output to the initial bytes specified in the configuration.
|
||||||
|
/// Useful for previewing file contents without reading everything.
|
||||||
|
///
|
||||||
|
/// # Fields
|
||||||
|
///
|
||||||
|
/// * `remaining` - Number of bytes left to read before stopping.
|
||||||
impl HeadBytesFilter {
|
impl HeadBytesFilter {
|
||||||
/// Creates a new `HeadBytesFilter` that will read up to the specified number of bytes.
|
/// Creates a new `HeadBytesFilter` that will read up to the specified number of bytes.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `count` - The maximum number of bytes to read from the input
|
/// * `count` - The maximum number of bytes to read from the input.
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
///
|
///
|
||||||
/// * `Self` - A new instance of `HeadBytesFilter`
|
/// A new instance configured to read at most `count` bytes.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let filter = HeadBytesFilter::new(1024);
|
||||||
|
/// assert_eq!(filter.remaining, 1024);
|
||||||
|
/// ```
|
||||||
pub fn new(count: usize) -> Self {
|
pub fn new(count: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
remaining: count,
|
remaining: count,
|
||||||
@@ -25,19 +48,31 @@ impl HeadBytesFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Filters input by reading only the first N bytes and writing them to the output.
|
||||||
|
///
|
||||||
|
/// Reads from the input in chunks until the byte limit is reached or EOF, then writes
|
||||||
|
/// the collected bytes to the output. Stops early if the limit is zero.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `reader` - Boxed mutable reference to the input data stream.
|
||||||
|
/// * `writer` - Boxed mutable reference to the output stream.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// * `Result<()>` - Success if filtering completes, or I/O error.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// * `io::Error` from reading or writing operations.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// // Assuming a filter chain with head_bytes(5)
|
||||||
|
/// // Input "Hello World" becomes "Hello"
|
||||||
|
/// ```
|
||||||
impl FilterPlugin for HeadBytesFilter {
|
impl FilterPlugin for HeadBytesFilter {
|
||||||
/// Filters the input by reading only the first N bytes and writing them to the output.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// * `reader` - A boxed mutable reference to the input reader providing the data stream
|
|
||||||
/// * `writer` - A boxed mutable reference to the output writer where filtered data is sent
|
|
||||||
///
|
|
||||||
/// # Returns
|
|
||||||
///
|
|
||||||
/// * `Result<()>` -
|
|
||||||
/// * `Ok(())` on success
|
|
||||||
/// * `Err(io::Error)` if reading or writing fails
|
|
||||||
fn filter(&mut self, mut reader: Box<&mut dyn Read>, mut writer: Box<&mut dyn Write>) -> Result<()> {
|
fn filter(&mut self, mut reader: Box<&mut dyn Read>, mut writer: Box<&mut dyn Write>) -> Result<()> {
|
||||||
if self.remaining == 0 {
|
if self.remaining == 0 {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -58,9 +93,11 @@ impl FilterPlugin for HeadBytesFilter {
|
|||||||
|
|
||||||
/// Clones this filter into a new boxed instance.
|
/// Clones this filter into a new boxed instance.
|
||||||
///
|
///
|
||||||
|
/// Creates an independent copy with the same configuration.
|
||||||
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
///
|
///
|
||||||
/// * `Box<dyn FilterPlugin>` - A new boxed clone of this filter
|
/// A new `Box<dyn FilterPlugin>` clone.
|
||||||
fn clone_box(&self) -> Box<dyn FilterPlugin> {
|
fn clone_box(&self) -> Box<dyn FilterPlugin> {
|
||||||
Box::new(Self {
|
Box::new(Self {
|
||||||
remaining: self.remaining,
|
remaining: self.remaining,
|
||||||
@@ -69,9 +106,11 @@ impl FilterPlugin for HeadBytesFilter {
|
|||||||
|
|
||||||
/// Returns the configuration options for this filter.
|
/// Returns the configuration options for this filter.
|
||||||
///
|
///
|
||||||
|
/// Defines the "count" parameter as required with no default.
|
||||||
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
///
|
///
|
||||||
/// * `Vec<FilterOption>` - A vector describing the filter's configurable parameters
|
/// Vector of `FilterOption` describing parameters.
|
||||||
fn options(&self) -> Vec<FilterOption> {
|
fn options(&self) -> Vec<FilterOption> {
|
||||||
vec![
|
vec![
|
||||||
FilterOption {
|
FilterOption {
|
||||||
@@ -84,20 +123,43 @@ impl FilterPlugin for HeadBytesFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A filter that reads the first N lines from the input stream.
|
/// A filter that reads the first N lines from the input stream.
|
||||||
|
/// A filter that reads the first N lines from the input stream.
|
||||||
|
///
|
||||||
|
/// Limits output to the initial lines specified, writing each full line to output.
|
||||||
|
/// Handles line endings properly using buffered reading.
|
||||||
|
///
|
||||||
|
/// # Fields
|
||||||
|
///
|
||||||
|
/// * `remaining` - Number of lines left to read before stopping.
|
||||||
pub struct HeadLinesFilter {
|
pub struct HeadLinesFilter {
|
||||||
remaining: usize,
|
remaining: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A filter that reads the first N lines from the input stream.
|
||||||
|
///
|
||||||
|
/// Limits output to the initial lines specified, writing each full line to output.
|
||||||
|
/// Handles line endings properly using buffered reading.
|
||||||
|
///
|
||||||
|
/// # Fields
|
||||||
|
///
|
||||||
|
/// * `remaining` - Number of lines left to read before stopping.
|
||||||
impl HeadLinesFilter {
|
impl HeadLinesFilter {
|
||||||
/// Creates a new `HeadLinesFilter` that will read up to the specified number of lines.
|
/// Creates a new `HeadLinesFilter` that will read up to the specified number of lines.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `count` - The maximum number of lines to read from the input
|
/// * `count` - The maximum number of lines to read from the input.
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
///
|
///
|
||||||
/// * `Self` - A new instance of `HeadLinesFilter`
|
/// A new instance configured to read at most `count` lines.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let filter = HeadLinesFilter::new(3);
|
||||||
|
/// assert_eq!(filter.remaining, 3);
|
||||||
|
/// ```
|
||||||
pub fn new(count: usize) -> Self {
|
pub fn new(count: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
remaining: count,
|
remaining: count,
|
||||||
@@ -105,19 +167,30 @@ impl HeadLinesFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Filters input by reading only the first N lines and writing them to the output.
|
||||||
|
///
|
||||||
|
/// Uses buffered line reading to process input line-by-line until the limit or EOF.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `reader` - Boxed mutable reference to the input data stream.
|
||||||
|
/// * `writer` - Boxed mutable reference to the output stream.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// * `Result<()>` - Success if filtering completes, or I/O error.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// * `io::Error` from line reading or writing operations.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// // Assuming a filter chain with head_lines(2)
|
||||||
|
/// // Input "Line1\nLine2\nLine3" becomes "Line1\nLine2\n"
|
||||||
|
/// ```
|
||||||
impl FilterPlugin for HeadLinesFilter {
|
impl FilterPlugin for HeadLinesFilter {
|
||||||
/// Filters the input by reading only the first N lines and writing them to the output.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// * `reader` - A boxed mutable reference to the input reader providing the data stream
|
|
||||||
/// * `writer` - A boxed mutable reference to the output writer where filtered data is sent
|
|
||||||
///
|
|
||||||
/// # Returns
|
|
||||||
///
|
|
||||||
/// * `Result<()>` -
|
|
||||||
/// * `Ok(())` on success
|
|
||||||
/// * `Err(io::Error)` if reading or writing fails
|
|
||||||
fn filter(&mut self, mut reader: Box<&mut dyn Read>, mut writer: Box<&mut dyn Write>) -> Result<()> {
|
fn filter(&mut self, mut reader: Box<&mut dyn Read>, mut writer: Box<&mut dyn Write>) -> Result<()> {
|
||||||
if self.remaining == 0 {
|
if self.remaining == 0 {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -137,9 +210,11 @@ impl FilterPlugin for HeadLinesFilter {
|
|||||||
|
|
||||||
/// Clones this filter into a new boxed instance.
|
/// Clones this filter into a new boxed instance.
|
||||||
///
|
///
|
||||||
|
/// Creates an independent copy with the same configuration.
|
||||||
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
///
|
///
|
||||||
/// * `Box<dyn FilterPlugin>` - A new boxed clone of this filter
|
/// A new `Box<dyn FilterPlugin>` clone.
|
||||||
fn clone_box(&self) -> Box<dyn FilterPlugin> {
|
fn clone_box(&self) -> Box<dyn FilterPlugin> {
|
||||||
Box::new(Self {
|
Box::new(Self {
|
||||||
remaining: self.remaining,
|
remaining: self.remaining,
|
||||||
@@ -148,9 +223,11 @@ impl FilterPlugin for HeadLinesFilter {
|
|||||||
|
|
||||||
/// Returns the configuration options for this filter.
|
/// Returns the configuration options for this filter.
|
||||||
///
|
///
|
||||||
|
/// Defines the "count" parameter as required with no default.
|
||||||
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
///
|
///
|
||||||
/// * `Vec<FilterOption>` - A vector describing the filter's configurable parameters
|
/// Vector of `FilterOption` describing parameters.
|
||||||
fn options(&self) -> Vec<FilterOption> {
|
fn options(&self) -> Vec<FilterOption> {
|
||||||
vec![
|
vec![
|
||||||
FilterOption {
|
FilterOption {
|
||||||
|
|||||||
37
src/lib.rs
37
src/lib.rs
@@ -2,6 +2,32 @@
|
|||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![allow(unused_imports)]
|
#![allow(unused_imports)]
|
||||||
|
|
||||||
|
//! Keep library for managing temporary files with compression and metadata.
|
||||||
|
//!
|
||||||
|
//! This library provides core functionality for the Keep application, including
|
||||||
|
//! database operations, compression engines, item services, and plugin systems
|
||||||
|
//! for metadata and filtering. It supports CLI modes, server APIs, and plugin
|
||||||
|
//! registration via ctors.
|
||||||
|
//!
|
||||||
|
//! # Usage
|
||||||
|
//!
|
||||||
|
//! Add to Cargo.toml and use re-exported types:
|
||||||
|
//! ```toml
|
||||||
|
//! [dependencies]
|
||||||
|
//! keep = "0.1"
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! use keep::Args;
|
||||||
|
//! let args = Args::parse();
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! # Features
|
||||||
|
//!
|
||||||
|
//! - `server`: Enables Axum-based HTTP server.
|
||||||
|
//! - `gzip`, `lz4`: Built-in compression support.
|
||||||
|
//! - `magic`: File type detection via libmagic.
|
||||||
|
|
||||||
// Re-export modules for testing
|
// Re-export modules for testing
|
||||||
pub mod common;
|
pub mod common;
|
||||||
pub mod compression_engine;
|
pub mod compression_engine;
|
||||||
@@ -39,7 +65,16 @@ use meta_plugin::{
|
|||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use meta_plugin::magic_file;
|
use meta_plugin::magic_file;
|
||||||
|
|
||||||
// Initialize plugins at library load time
|
/// Initializes plugins at library load time.
|
||||||
|
///
|
||||||
|
/// Ensures all filter and meta plugins are registered via their ctors.
|
||||||
|
/// Call this early in application startup if needed (though ctors handle most cases).
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// keep::init_plugins();
|
||||||
|
/// ```
|
||||||
pub fn init_plugins() {
|
pub fn init_plugins() {
|
||||||
// This will be expanded in Step 3 implementation
|
// This will be expanded in Step 3 implementation
|
||||||
// For now, the ctors handle registration
|
// For now, the ctors handle registration
|
||||||
|
|||||||
Reference in New Issue
Block a user