docs: Add Rustdoc examples to server common types and compression engine

Co-authored-by: aider (openai/andrew/openrouter/sonoma-sky-alpha) <aider@aider.chat>
This commit is contained in:
Andrew Phillips
2025-09-10 14:05:24 -03:00
parent 46a245a59a
commit 6cff3bd165
2 changed files with 144 additions and 103 deletions

View File

@@ -1,8 +1,18 @@
```rust
/// GZip compression engine module.
///
/// This module provides the implementation for GZip compression and decompression
/// using the `flate2` crate. It includes the main `CompressionEngineGZip` struct
/// and supporting types for handling GZip streams.
///
/// # Usage
///
/// ```rust
/// use keep::compression_engine::get_compression_engine;
/// let engine = get_compression_engine(keep::compression_engine::CompressionType::GZip)
/// .expect("GZip engine creation failed");
/// let reader = engine.open("/path/to/file.gz".into()).expect("Open failed");
/// ```
use anyhow::Result;
use log::*;
use std::fs::File;
@@ -16,11 +26,20 @@ use flate2::write::GzEncoder;
use crate::compression_engine::CompressionEngine;
```rust
/// GZip compression engine implementation.
///
/// This struct provides the functionality to compress and decompress data using
/// the GZip algorithm. It implements the `CompressionEngine` trait for integration
/// with the compression service.
///
/// # Examples
///
/// ```rust
/// let engine = keep::compression_engine::get_compression_engine(keep::compression_engine::CompressionType::GZip)
/// .expect("Failed to get GZip engine");
/// assert!(engine.is_supported());
/// ```
#[derive(Debug, Eq, PartialEq, Clone, Default)]
pub struct CompressionEngineGZip {}
@@ -30,6 +49,12 @@ impl CompressionEngineGZip {
/// # Returns
///
/// A new `CompressionEngineGZip` instance.
///
/// # Examples
///
/// ```
/// let engine = CompressionEngineGZip::new();
/// ```
pub fn new() -> CompressionEngineGZip {
CompressionEngineGZip {}
}
@@ -44,6 +69,13 @@ impl CompressionEngine for CompressionEngineGZip {
/// # Returns
///
/// Always returns `true` since GZip is built-in.
///
/// # Examples
///
/// ```
/// let engine = CompressionEngineGZip::new();
/// assert!(engine.is_supported());
/// ```
fn is_supported(&self) -> bool {
true
}
@@ -60,6 +92,16 @@ impl CompressionEngine for CompressionEngineGZip {
/// # Returns
///
/// * `Result<Box<dyn Read>>` - A boxed reader that decompresses the GZip file on read.
///
/// # Errors
///
/// * `anyhow::Error` - If the file cannot be opened or decoded.
///
/// # Examples
///
/// ```
/// let reader = engine.open("/path/to/file.gz".into()).expect("Open failed");
/// ```
fn open(&self, file_path: PathBuf) -> Result<Box<dyn Read>> {
debug!("COMPRESSION: Opening {:?} using {:?}", file_path, *self);
@@ -80,6 +122,16 @@ impl CompressionEngine for CompressionEngineGZip {
/// # Returns
///
/// * `Result<Box<dyn Write>>` - A boxed writer that compresses data using GZip on write.
///
/// # Errors
///
/// * `anyhow::Error` - If the file cannot be created or encoder fails.
///
/// # Examples
///
/// ```
/// let writer = engine.create("/path/to/file.gz".into()).expect("Create failed");
/// ```
fn create(&self, file_path: PathBuf) -> Result<Box<dyn Write>> {
debug!("COMPRESSION: Writting to {:?} using {:?}", file_path, *self);
@@ -90,10 +142,20 @@ impl CompressionEngine for CompressionEngineGZip {
}
}
```rust
/// Auto-finishing GZip encoder that automatically calls finish on drop.
///
/// This wrapper ensures that the GZip stream is properly closed even if the
/// writer is dropped unexpectedly, preventing incomplete compression files.
///
/// # Examples
///
/// ```rust
/// let file = File::create("test.gz").unwrap();
/// let encoder = GzEncoder::new(file, Compression::default());
/// let auto_encoder = AutoFinishGzEncoder::new(encoder);
/// // Encoder will finish on drop
/// ```
pub struct AutoFinishGzEncoder<W: Write> {
encoder: Option<GzEncoder<W>>,
}
@@ -108,6 +170,14 @@ impl<W: Write> AutoFinishGzEncoder<W> {
/// # Returns
///
/// A new `AutoFinishGzEncoder` instance.
///
/// # Examples
///
/// ```
/// let file = File::create("test.gz").unwrap();
/// let encoder = GzEncoder::new(file, Compression::default());
/// let auto_encoder = AutoFinishGzEncoder::new(encoder);
/// ```
fn new(gz_encoder: GzEncoder<W>) -> AutoFinishGzEncoder<W> {
AutoFinishGzEncoder {
encoder: Some(gz_encoder),
@@ -120,6 +190,10 @@ impl<W: Write> Drop for AutoFinishGzEncoder<W> {
///
/// This method ensures the GZip stream is properly closed by calling `finish()`
/// on the underlying encoder.
///
/// # Errors
///
/// Errors during finish are logged but ignored.
fn drop(&mut self) {
if let Some(encoder) = self.encoder.take() {
debug!("COMPRESSION: Finishing");
@@ -138,6 +212,10 @@ impl<W: Write> Write for AutoFinishGzEncoder<W> {
/// # Returns
///
/// * `io::Result<usize>` - The number of bytes written or an I/O error.
///
/// # Errors
///
/// Propagates errors from the underlying encoder.
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.encoder.as_mut().unwrap().write(buf)
}
@@ -147,6 +225,10 @@ impl<W: Write> Write for AutoFinishGzEncoder<W> {
/// # Returns
///
/// * `io::Result<()>` - Success or an I/O error.
///
/// # Errors
///
/// Propagates errors from the underlying encoder.
fn flush(&mut self) -> io::Result<()> {
self.encoder.as_mut().unwrap().flush()
}

View File

@@ -3,6 +3,14 @@
/// This module provides shared structures, functions, and middleware used across
/// different parts of the server implementation, including configuration, state
/// management, API responses, authentication, and logging.
///
/// # Usage
///
/// ```rust
/// use keep::modes::server::common::{ServerConfig, AppState};
/// let config = ServerConfig { address: "127.0.0.1".to_string(), ..Default::default() };
/// let state = AppState { /* ... */ };
/// ```
use anyhow::Result;
use axum::{
extract::{Request, ConnectInfo},
@@ -26,6 +34,17 @@ use crate::services::item_service::ItemService;
///
/// This struct holds the configuration parameters for the HTTP server, including
/// binding address, port, and authentication settings.
///
/// # Examples
///
/// ```
/// let config = ServerConfig {
/// address: "127.0.0.1".to_string(),
/// port: Some(8080),
/// password: None,
/// password_hash: None,
/// };
/// ```
#[derive(Debug, Clone)]
pub struct ServerConfig {
/// Server bind address.
@@ -50,11 +69,6 @@ pub struct ServerConfig {
pub password_hash: Option<String>,
}
/// Application state shared across all routes.
///
/// This struct encapsulates the shared state that is accessible to all request handlers,
/// including database connections, file paths, services, and configuration.
#[derive(Clone)]
/// Application state shared across all routes.
///
/// This struct encapsulates the shared state that is accessible to all request handlers,
@@ -62,7 +76,10 @@ pub struct ServerConfig {
///
/// # Examples
///
/// ```
/// ```rust
/// use keep::modes::server::common::AppState;
/// use std::sync::Arc;
/// use tokio::sync::Mutex;
/// let state = AppState {
/// db: Arc::new(Mutex::new(conn)),
/// data_dir: PathBuf::from("/data"),
@@ -71,6 +88,7 @@ pub struct ServerConfig {
/// settings: Arc::new(settings),
/// };
/// ```
#[derive(Clone)]
pub struct AppState {
/// Database connection wrapped in Arc<Mutex>.
///
@@ -95,11 +113,6 @@ pub struct AppState {
pub settings: Arc<crate::config::Settings>,
}
/// Standard API response wrapper containing success status, data payload, and error information.
///
/// This generic type is used for all API responses to provide a consistent structure across
/// different endpoints.
#[derive(Debug, Serialize, Deserialize, ToSchema)]
/// Standard API response wrapper containing success status, data payload, and error information.
///
/// This generic type is used for all API responses to provide a consistent structure across
@@ -111,13 +124,15 @@ pub struct AppState {
///
/// # Examples
///
/// ```
/// ```rust
/// use keep::modes::server::common::ApiResponse;
/// let response: ApiResponse<Vec<ItemInfo>> = ApiResponse {
/// success: true,
/// data: Some(items),
/// error: None,
/// };
/// ```
#[derive(Debug, Serialize, Deserialize, ToSchema)]
#[schema(description = "Standard API response wrapper containing success status, data payload, and error information")]
pub struct ApiResponse<T> {
/// Success indicator.
@@ -134,23 +149,21 @@ pub struct ApiResponse<T> {
pub error: Option<String>,
}
/// Response type for list of item information.
///
/// Specialized response for endpoints that return multiple items.
#[derive(Serialize, Deserialize, ToSchema)]
/// Response type for list of item information.
///
/// Specialized response for endpoints that return multiple items.
///
/// # Examples
///
/// ```
/// ```rust
/// use keep::modes::server::common::ItemInfoListResponse;
/// let response = ItemInfoListResponse {
/// success: true,
/// data: Some(vec![item_info]),
/// error: None,
/// };
/// ```
#[derive(Serialize, Deserialize, ToSchema)]
pub struct ItemInfoListResponse {
/// Success indicator.
///
@@ -166,23 +179,21 @@ pub struct ItemInfoListResponse {
pub error: Option<String>,
}
/// Response type for single item information.
///
/// Specialized response for endpoints that return a single item's details.
#[derive(Serialize, Deserialize, ToSchema)]
/// Response type for single item information.
///
/// Specialized response for endpoints that return a single item's details.
///
/// # Examples
///
/// ```
/// ```rust
/// use keep::modes::server::common::ItemInfoResponse;
/// let response = ItemInfoResponse {
/// success: true,
/// data: Some(item_info),
/// error: None,
/// };
/// ```
#[derive(Serialize, Deserialize, ToSchema)]
pub struct ItemInfoResponse {
/// Success indicator.
///
@@ -198,23 +209,21 @@ pub struct ItemInfoResponse {
pub error: Option<String>,
}
/// Response type for item content information.
///
/// Specialized response for endpoints that return item content and related metadata.
#[derive(Serialize, Deserialize, ToSchema)]
/// Response type for item content information.
///
/// Specialized response for endpoints that return item content and related metadata.
///
/// # Examples
///
/// ```
/// ```rust
/// use keep::modes::server::common::ItemContentInfoResponse;
/// let response = ItemContentInfoResponse {
/// success: true,
/// data: Some(content_info),
/// error: None,
/// };
/// ```
#[derive(Serialize, Deserialize, ToSchema)]
pub struct ItemContentInfoResponse {
/// Success indicator.
///
@@ -230,23 +239,21 @@ pub struct ItemContentInfoResponse {
pub error: Option<String>,
}
/// Response type for metadata.
///
/// Specialized response for metadata-only endpoints.
#[derive(Serialize, Deserialize, ToSchema)]
/// Response type for metadata.
///
/// Specialized response for metadata-only endpoints.
///
/// # Examples
///
/// ```
/// ```rust
/// use keep::modes::server::common::MetadataResponse;
/// let response = MetadataResponse {
/// success: true,
/// data: Some(meta_map),
/// error: None,
/// };
/// ```
#[derive(Serialize, Deserialize, ToSchema)]
pub struct MetadataResponse {
/// Success indicator.
///
@@ -262,23 +269,21 @@ pub struct MetadataResponse {
pub error: Option<String>,
}
/// Response type for status information.
///
/// Specialized response for system status endpoints.
#[derive(Serialize, Deserialize, ToSchema)]
/// Response type for status information.
///
/// Specialized response for system status endpoints.
///
/// # Examples
///
/// ```
/// ```rust
/// use keep::modes::server::common::StatusInfoResponse;
/// let response = StatusInfoResponse {
/// success: true,
/// data: Some(status_info),
/// error: None,
/// };
/// ```
#[derive(Serialize, Deserialize, ToSchema)]
pub struct StatusInfoResponse {
/// Success indicator.
///
@@ -294,11 +299,6 @@ pub struct StatusInfoResponse {
pub error: Option<String>,
}
/// Complete information about a stored item including metadata and tags.
///
/// This structure represents the full details of an item, combining basic item
/// properties with associated tags and metadata.
#[derive(Serialize, Deserialize, ToSchema)]
/// Complete information about a stored item including metadata and tags.
///
/// This structure represents the full details of an item, combining basic item
@@ -306,7 +306,9 @@ pub struct StatusInfoResponse {
///
/// # Examples
///
/// ```
/// ```rust
/// use keep::modes::server::common::ItemInfo;
/// use std::collections::HashMap;
/// let item_info = ItemInfo {
/// id: 42,
/// ts: "2023-12-01T15:30:45Z".to_string(),
@@ -316,6 +318,7 @@ pub struct StatusInfoResponse {
/// metadata: HashMap::from([("mime_type".to_string(), "text/plain".to_string())]),
/// };
/// ```
#[derive(Serialize, Deserialize, ToSchema)]
#[schema(description = "Complete information about a stored item including metadata and tags")]
pub struct ItemInfo {
/// Item ID.
@@ -350,17 +353,6 @@ pub struct ItemInfo {
pub metadata: HashMap<String, String>,
}
/// Item information including content and metadata, with binary detection.
///
/// This structure provides item details along with its content, handling binary
/// content detection and safe string representation.
///
/// # Fields
///
/// * `metadata` - Flattened metadata HashMap.
/// * `content` - Optional string content (text only).
/// * `binary` - True if binary content.
#[derive(Serialize, Deserialize, ToSchema)]
/// Item information including content and metadata, with binary detection.
///
/// This structure provides item details along with its content, handling binary
@@ -368,13 +360,16 @@ pub struct ItemInfo {
///
/// # Examples
///
/// ```
/// ```rust
/// use keep::modes::server::common::ItemContentInfo;
/// use std::collections::HashMap;
/// let content_info = ItemContentInfo {
/// metadata: HashMap::from([("mime_type".to_string(), "text/plain".to_string())]),
/// content: Some("Hello, world!".to_string()),
/// binary: false,
/// };
/// ```
#[derive(Serialize, Deserialize, ToSchema)]
#[schema(description = "Item information including content and metadata, with binary detection")]
pub struct ItemContentInfo {
/// Metadata hashmap.
@@ -395,23 +390,17 @@ pub struct ItemContentInfo {
pub binary: bool,
}
/// Query parameters for tags.
///
/// Structure for handling tag-based query parameters in API requests.
///
/// # Fields
///
/// * `tags` - Optional comma-separated tags for filtering.
#[derive(Debug, Deserialize)]
/// Query parameters for tags.
///
/// Structure for handling tag-based query parameters in API requests.
///
/// # Examples
///
/// ```
/// ```rust
/// use keep::modes::server::common::TagsQuery;
/// let query = TagsQuery { tags: Some("tag1,tag2".to_string()) };
/// ```
#[derive(Debug, Deserialize)]
pub struct TagsQuery {
/// Optional comma-separated tags.
///
@@ -419,24 +408,14 @@ pub struct TagsQuery {
pub tags: Option<String>,
}
/// Query parameters for listing items.
///
/// Structure for pagination and sorting parameters in item listing endpoints.
///
/// # Fields
///
/// * `tags` - Optional tags for filtering.
/// * `order` - Optional sort: "newest" or "oldest".
/// * `start` - Optional start index.
/// * `count` - Optional item limit.
#[derive(Debug, Deserialize)]
/// Query parameters for listing items.
///
/// Structure for pagination and sorting parameters in item listing endpoints.
///
/// # Examples
///
/// ```
/// ```rust
/// use keep::modes::server::common::ListItemsQuery;
/// let query = ListItemsQuery {
/// tags: Some("important".to_string()),
/// order: Some("newest".to_string()),
@@ -444,6 +423,7 @@ pub struct TagsQuery {
/// count: Some(10),
/// };
/// ```
#[derive(Debug, Deserialize)]
pub struct ListItemsQuery {
/// Optional comma-separated tags for filtering.
///
@@ -463,25 +443,14 @@ pub struct ListItemsQuery {
pub count: Option<u32>,
}
/// Query parameters for item retrieval.
///
/// Structure for content retrieval parameters, including binary handling and streaming options.
///
/// # Fields
///
/// * `allow_binary` - Allow binary (default true).
/// * `offset` - Byte offset (default 0).
/// * `length` - Byte length (default 0 = all).
/// * `stream` - Enable streaming (default false).
/// * `as_meta` - Return as JSON metadata (default false).
#[derive(Debug, Deserialize, utoipa::ToSchema)]
/// Query parameters for item retrieval.
///
/// Structure for content retrieval parameters, including binary handling and streaming options.
///
/// # Examples
///
/// ```
/// ```rust
/// use keep::modes::server::common::ItemQuery;
/// let query = ItemQuery {
/// allow_binary: true,
/// offset: 0,
@@ -490,6 +459,7 @@ pub struct ListItemsQuery {
/// as_meta: false,
/// };
/// ```
#[derive(Debug, Deserialize, utoipa::ToSchema)]
pub struct ItemQuery {
/// Allow binary content (default: true).
///
@@ -518,26 +488,14 @@ pub struct ItemQuery {
pub as_meta: bool,
}
/// Query parameters for item content retrieval.
///
/// Extended query parameters for content-specific operations, including tag filtering.
///
/// # Fields
///
/// * `tags` - Optional tags for filtering.
/// * `allow_binary` - Allow binary (default true).
/// * `offset` - Byte offset (default 0).
/// * `length` - Byte length (default 0 = all).
/// * `stream` - Enable streaming (default false).
/// * `as_meta` - Return as JSON metadata (default false).
#[derive(Debug, Deserialize, utoipa::ToSchema)]
/// Query parameters for item content retrieval.
///
/// Extended query parameters for content-specific operations, including tag filtering.
///
/// # Examples
///
/// ```
/// ```rust
/// use keep::modes::server::common::ItemContentQuery;
/// let query = ItemContentQuery {
/// tags: Some("important".to_string()),
/// allow_binary: true,
@@ -547,6 +505,7 @@ pub struct ItemQuery {
/// as_meta: false,
/// };
/// ```
#[derive(Debug, Deserialize, utoipa::ToSchema)]
pub struct ItemContentQuery {
/// Optional comma-separated tags for filtering.
///