perf: replace dyn trait objects with concrete types to eliminate vtable overhead
Remove async-trait dependency and use native Rust async fn in traits. Replace Arc<dyn Trait> with Arc<ConcreteType> throughout the codebase to enable monomorphization and eliminate dynamic dispatch overhead. Key changes: - Remove write-behind cache (no implementation existed) - Fix should_transcode static method call - Use ContactStorageAdapter directly instead of dyn AddressBookUseCase - Clean up unused trait imports across services and DI https://claude.ai/code/session_01EbAFEfyJNLRmJHmmYDX3Tt
This commit is contained in:
@@ -3,7 +3,6 @@ use crate::domain::entities::app_password::AppPassword;
|
||||
use crate::domain::entities::device_code::DeviceCode;
|
||||
use crate::domain::entities::session::Session;
|
||||
use crate::domain::entities::user::User;
|
||||
use async_trait::async_trait;
|
||||
|
||||
// ============================================================================
|
||||
// Cryptography Ports - Extracted from Domain to maintain Clean Architecture
|
||||
@@ -16,7 +15,6 @@ use async_trait::async_trait;
|
||||
///
|
||||
/// Methods are async because implementations (e.g. Argon2) are CPU-intensive
|
||||
/// and must run on a blocking thread pool to avoid starving Tokio workers.
|
||||
#[async_trait]
|
||||
pub trait PasswordHasherPort: Send + Sync + 'static {
|
||||
/// Hash a plain text password
|
||||
async fn hash_password(&self, password: &str) -> Result<String, DomainError>;
|
||||
@@ -69,7 +67,6 @@ pub trait TokenServicePort: Send + Sync + 'static {
|
||||
// Storage Ports
|
||||
// ============================================================================
|
||||
|
||||
#[async_trait]
|
||||
pub trait UserStoragePort: Send + Sync + 'static {
|
||||
/// Creates a new user
|
||||
async fn create_user(&self, user: User) -> Result<User, DomainError>;
|
||||
@@ -153,7 +150,6 @@ pub struct OidcIdClaims {
|
||||
}
|
||||
|
||||
/// Port for OIDC operations — implemented in infrastructure layer
|
||||
#[async_trait]
|
||||
pub trait OidcServicePort: Send + Sync + 'static {
|
||||
/// Get the authorization URL for redirecting the user to the IdP.
|
||||
/// Includes PKCE code_challenge (S256) and nonce for ID token binding.
|
||||
@@ -187,7 +183,6 @@ pub trait OidcServicePort: Send + Sync + 'static {
|
||||
fn provider_name(&self) -> &str;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait SessionStoragePort: Send + Sync + 'static {
|
||||
/// Creates a new session
|
||||
async fn create_session(&self, session: Session) -> Result<Session, DomainError>;
|
||||
@@ -209,7 +204,6 @@ pub trait SessionStoragePort: Send + Sync + 'static {
|
||||
// Device Authorization Grant Port (RFC 8628)
|
||||
// ============================================================================
|
||||
|
||||
#[async_trait]
|
||||
pub trait DeviceCodeStoragePort: Send + Sync + 'static {
|
||||
/// Persist a new device code flow
|
||||
async fn create_device_code(&self, device_code: DeviceCode) -> Result<DeviceCode, DomainError>;
|
||||
@@ -238,7 +232,6 @@ pub trait DeviceCodeStoragePort: Send + Sync + 'static {
|
||||
// ============================================================================
|
||||
|
||||
/// Storage port for application-specific passwords (HTTP Basic Auth for DAV clients).
|
||||
#[async_trait]
|
||||
pub trait AppPasswordStoragePort: Send + Sync + 'static {
|
||||
/// Persist a new app password (hash already computed).
|
||||
async fn create(&self, app_password: AppPassword) -> Result<AppPassword, DomainError>;
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
//! implementation details.
|
||||
|
||||
use crate::common::errors::DomainError;
|
||||
use async_trait::async_trait;
|
||||
use bytes::Bytes;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
@@ -30,7 +29,6 @@ pub struct WriteBehindStatsDto {
|
||||
/// Provides deferred write semantics: small files are held in memory
|
||||
/// and the response is returned immediately, while actual disk writes
|
||||
/// happen asynchronously in the background.
|
||||
#[async_trait]
|
||||
pub trait WriteBehindCachePort: Send + Sync + 'static {
|
||||
/// Check if a file size is eligible for write-behind caching.
|
||||
fn is_eligible_size(&self, size: usize) -> bool;
|
||||
@@ -82,7 +80,6 @@ pub struct CachedMetadataDto {
|
||||
///
|
||||
/// Provides fast lookups for existence, size, timestamps and MIME types
|
||||
/// without hitting the filesystem on every request.
|
||||
#[async_trait]
|
||||
pub trait MetadataCachePort: Send + Sync + 'static {
|
||||
/// Get cached metadata for a path, or `None` on miss / expired.
|
||||
async fn get_metadata(&self, path: &Path) -> Option<CachedMetadataDto>;
|
||||
@@ -106,7 +103,6 @@ pub trait MetadataCachePort: Send + Sync + 'static {
|
||||
///
|
||||
/// Implementations should use LRU eviction and respect size limits so that
|
||||
/// the application layer never needs to know the concrete cache type.
|
||||
#[async_trait]
|
||||
pub trait ContentCachePort: Send + Sync + 'static {
|
||||
/// Check whether a file of the given size should be cached.
|
||||
fn should_cache(&self, size: usize) -> bool;
|
||||
|
||||
@@ -3,11 +3,9 @@ use crate::application::dtos::calendar_dto::{
|
||||
UpdateCalendarDto, UpdateEventDto,
|
||||
};
|
||||
use crate::common::errors::DomainError;
|
||||
use async_trait::async_trait;
|
||||
use chrono::{DateTime, Utc};
|
||||
|
||||
/// Port for external calendar storage mechanisms
|
||||
#[async_trait]
|
||||
pub trait CalendarStoragePort: Send + Sync + 'static {
|
||||
// Calendar operations
|
||||
async fn create_calendar(
|
||||
@@ -111,7 +109,6 @@ pub trait CalendarStoragePort: Send + Sync + 'static {
|
||||
/// All methods require an explicit `user_id` parameter for authorization.
|
||||
/// The CalDAV protocol handler extracts the user identity from JWT claims
|
||||
/// and passes it through.
|
||||
#[async_trait]
|
||||
pub trait CalendarUseCase: Send + Sync + 'static {
|
||||
// Calendar operations
|
||||
async fn create_calendar(
|
||||
|
||||
@@ -7,11 +7,9 @@ use crate::application::dtos::contact_dto::{
|
||||
GroupMembershipDto, UpdateContactDto, UpdateContactGroupDto,
|
||||
};
|
||||
use crate::common::errors::DomainError;
|
||||
use async_trait::async_trait;
|
||||
|
||||
pub type CardDavRepositoryError = DomainError;
|
||||
|
||||
#[async_trait]
|
||||
pub trait AddressBookUseCase: Send + Sync + 'static {
|
||||
// Address Book operations
|
||||
async fn create_address_book(
|
||||
@@ -57,7 +55,6 @@ pub trait AddressBookUseCase: Send + Sync + 'static {
|
||||
) -> Result<Vec<(String, bool)>, DomainError>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait ContactUseCase: Send + Sync + 'static {
|
||||
// Contact operations
|
||||
async fn create_contact(&self, dto: CreateContactDto) -> Result<ContactDto, DomainError>;
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
//! the specific upload implementation (TUS-like protocol, S3 multipart, etc.).
|
||||
|
||||
use crate::common::errors::DomainError;
|
||||
use async_trait::async_trait;
|
||||
use bytes::Bytes;
|
||||
use serde::Serialize;
|
||||
use std::path::PathBuf;
|
||||
@@ -53,7 +52,6 @@ pub struct UploadStatusResponseDto {
|
||||
/// Implementations manage upload sessions, chunk storage, reassembly,
|
||||
/// and cleanup, while the application layer only interacts through
|
||||
/// this abstraction.
|
||||
#[async_trait]
|
||||
pub trait ChunkedUploadPort: Send + Sync + 'static {
|
||||
/// Create a new upload session.
|
||||
///
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
//! compression implementations (gzip, zstd, etc.).
|
||||
|
||||
use crate::common::errors::DomainError;
|
||||
use async_trait::async_trait;
|
||||
|
||||
/// Compression level settings for file compression operations.
|
||||
///
|
||||
@@ -27,7 +26,6 @@ pub enum CompressionLevel {
|
||||
/// Implementations of this trait provide the actual compression logic
|
||||
/// (e.g., gzip, zstd) while the application layer remains agnostic
|
||||
/// of the specific algorithm used.
|
||||
#[async_trait]
|
||||
pub trait CompressionPort: Send + Sync + 'static {
|
||||
/// Compress data in memory.
|
||||
async fn compress_data(
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
//! content-addressable storage implementation.
|
||||
|
||||
use crate::common::errors::DomainError;
|
||||
use async_trait::async_trait;
|
||||
use bytes::Bytes;
|
||||
use futures::Stream;
|
||||
use serde::Serialize;
|
||||
@@ -92,7 +91,6 @@ pub struct DedupStatsDto {
|
||||
/// Implementations store files by their content hash, eliminating
|
||||
/// duplicate storage automatically. Multiple file references can
|
||||
/// point to the same physical blob.
|
||||
#[async_trait]
|
||||
pub trait DedupPort: Send + Sync + 'static {
|
||||
/// Store content with deduplication (from bytes).
|
||||
///
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
use crate::application::dtos::favorites_dto::{BatchFavoritesResult, FavoriteItemDto};
|
||||
use crate::common::errors::Result;
|
||||
use async_trait::async_trait;
|
||||
|
||||
/// Defines operations for managing user favorites
|
||||
#[async_trait]
|
||||
pub trait FavoritesUseCase: Send + Sync {
|
||||
/// Get all favorites for a user
|
||||
async fn get_favorites(&self, user_id: &str) -> Result<Vec<FavoriteItemDto>>;
|
||||
@@ -40,7 +38,6 @@ pub trait FavoritesUseCase: Send + Sync {
|
||||
/// Application services depend on this trait instead of
|
||||
/// accessing `PgPool` directly. The concrete implementation
|
||||
/// lives in `infrastructure::repositories::pg`.
|
||||
#[async_trait]
|
||||
pub trait FavoritesRepositoryPort: Send + Sync + 'static {
|
||||
/// Gets all favorites for a user.
|
||||
async fn get_favorites(&self, user_id: &str) -> Result<Vec<FavoriteItemDto>>;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use async_trait::async_trait;
|
||||
use bytes::Bytes;
|
||||
use futures::Stream;
|
||||
use std::path::Path;
|
||||
@@ -8,6 +7,9 @@ use std::sync::Arc;
|
||||
use crate::application::dtos::file_dto::FileDto;
|
||||
use crate::application::ports::storage_ports::CopyFolderTreeResult;
|
||||
use crate::common::errors::DomainError;
|
||||
use crate::application::services::file_management_service::FileManagementService;
|
||||
use crate::application::services::file_retrieval_service::FileRetrievalService;
|
||||
use crate::application::services::file_upload_service::FileUploadService;
|
||||
|
||||
// ─────────────────────────────────────────────────────
|
||||
// Upload port
|
||||
@@ -24,7 +26,6 @@ use crate::common::errors::DomainError;
|
||||
/// - Chunked uploads: chunks already on disk → `upload_file_from_path`
|
||||
/// - WebDAV PUT (new): handler streams to temp file → `update_file_streaming`
|
||||
/// - WebDAV PUT (small/compat): `create_file` / `update_file` spool internally
|
||||
#[async_trait]
|
||||
pub trait FileUploadUseCase: Send + Sync + 'static {
|
||||
/// Upload from a temp file already on disk (true streaming, ~256 KB RAM).
|
||||
///
|
||||
@@ -102,7 +103,6 @@ pub enum OptimizedFileContent {
|
||||
}
|
||||
|
||||
/// Primary port for file retrieval operations
|
||||
#[async_trait]
|
||||
pub trait FileRetrievalUseCase: Send + Sync + 'static {
|
||||
/// Gets a file by its ID
|
||||
async fn get_file(&self, id: &str) -> Result<FileDto, DomainError>;
|
||||
@@ -188,7 +188,6 @@ pub trait FileRetrievalUseCase: Send + Sync + 'static {
|
||||
// ─────────────────────────────────────────────────────
|
||||
|
||||
/// Primary port for file management operations
|
||||
#[async_trait]
|
||||
pub trait FileManagementUseCase: Send + Sync + 'static {
|
||||
/// Moves a file to another folder
|
||||
async fn move_file(
|
||||
@@ -241,7 +240,7 @@ pub trait FileManagementUseCase: Send + Sync + 'static {
|
||||
|
||||
/// Factory for creating file use case implementations
|
||||
pub trait FileUseCaseFactory: Send + Sync + 'static {
|
||||
fn create_file_upload_use_case(&self) -> Arc<dyn FileUploadUseCase>;
|
||||
fn create_file_retrieval_use_case(&self) -> Arc<dyn FileRetrievalUseCase>;
|
||||
fn create_file_management_use_case(&self) -> Arc<dyn FileManagementUseCase>;
|
||||
fn create_file_upload_use_case(&self) -> Arc<FileUploadService>;
|
||||
fn create_file_retrieval_use_case(&self) -> Arc<FileRetrievalService>;
|
||||
fn create_file_management_use_case(&self) -> Arc<FileManagementService>;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use async_trait::async_trait;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::application::dtos::folder_dto::{
|
||||
@@ -10,7 +9,6 @@ use crate::application::dtos::search_dto::{
|
||||
use crate::common::errors::DomainError;
|
||||
|
||||
/// Primary port for folder operations
|
||||
#[async_trait]
|
||||
pub trait FolderUseCase: Send + Sync + 'static {
|
||||
/// Creates a new folder
|
||||
async fn create_folder(&self, dto: CreateFolderDto) -> Result<FolderDto, DomainError>;
|
||||
@@ -89,7 +87,6 @@ pub trait FolderUseCase: Send + Sync + 'static {
|
||||
* All search processing (filtering, scoring, sorting, categorization)
|
||||
* is handled server-side in Rust for maximum efficiency.
|
||||
*/
|
||||
#[async_trait]
|
||||
pub trait SearchUseCase: Send + Sync + 'static {
|
||||
/// Performs a full search based on the specified criteria.
|
||||
///
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use async_trait::async_trait;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::common::errors::DomainError;
|
||||
@@ -10,7 +9,6 @@ pub use crate::domain::repositories::folder_repository::FolderRepository;
|
||||
use super::storage_ports::{FileReadPort, FileWritePort};
|
||||
|
||||
/// Secondary port for storage operations
|
||||
#[async_trait]
|
||||
pub trait StoragePort: Send + Sync + 'static {
|
||||
/// Resolves a domain path to a physical path
|
||||
fn resolve_path(&self, storage_path: &StoragePath) -> PathBuf;
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
use crate::application::dtos::recent_dto::RecentItemDto;
|
||||
use crate::common::errors::Result;
|
||||
use async_trait::async_trait;
|
||||
|
||||
/// Defines operations for managing user recent items
|
||||
#[async_trait]
|
||||
pub trait RecentItemsUseCase: Send + Sync {
|
||||
/// Get all recent items for a user
|
||||
async fn get_recent_items(
|
||||
@@ -36,7 +34,6 @@ pub trait RecentItemsUseCase: Send + Sync {
|
||||
///
|
||||
/// Abstracts access to the `auth.user_recent_files` table so that
|
||||
/// `RecentService` does not depend directly on `PgPool`.
|
||||
#[async_trait]
|
||||
pub trait RecentItemsRepositoryPort: Send + Sync + 'static {
|
||||
/// Gets the latest recent items for a user (ordered by date desc).
|
||||
async fn get_recent_items(&self, user_id: &str, limit: i32) -> Result<Vec<RecentItemDto>>;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
application::dtos::{
|
||||
@@ -9,7 +8,6 @@ use crate::{
|
||||
domain::entities::share::ShareItemType,
|
||||
};
|
||||
|
||||
#[async_trait]
|
||||
pub trait ShareUseCase: Send + Sync + 'static {
|
||||
/// Create a new shared link for a file or folder
|
||||
async fn create_shared_link(
|
||||
@@ -60,7 +58,6 @@ pub trait ShareUseCase: Send + Sync + 'static {
|
||||
async fn register_shared_link_access(&self, token: &str) -> Result<(), DomainError>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait ShareStoragePort: Send + Sync + 'static {
|
||||
async fn save_share(
|
||||
&self,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use async_trait::async_trait;
|
||||
use bytes::Bytes;
|
||||
use futures::Stream;
|
||||
use serde_json::Value;
|
||||
@@ -25,7 +24,6 @@ pub use crate::domain::repositories::folder_repository::FolderRepository;
|
||||
///
|
||||
/// Encapsulates every operation that queries state without modifying it:
|
||||
/// get, list, content, stream, mmap, range, path resolution.
|
||||
#[async_trait]
|
||||
pub trait FileReadPort: Send + Sync + 'static {
|
||||
/// Gets a file by its ID.
|
||||
async fn get_file(&self, id: &str) -> Result<File, DomainError>;
|
||||
@@ -199,7 +197,6 @@ pub struct CopyFolderTreeResult {
|
||||
///
|
||||
/// Covers: upload (buffered + streaming), move, delete, update,
|
||||
/// and deferred registration for the write-behind cache.
|
||||
#[async_trait]
|
||||
pub trait FileWritePort: Send + Sync + 'static {
|
||||
/// Streaming upload — saves a file from a temp file already on disk.
|
||||
///
|
||||
@@ -307,7 +304,6 @@ pub trait FileWritePort: Send + Sync + 'static {
|
||||
// ─────────────────────────────────────────────────────
|
||||
|
||||
/// Secondary port for file path resolution
|
||||
#[async_trait]
|
||||
pub trait FilePathResolutionPort: Send + Sync + 'static {
|
||||
/// Gets the storage path of a file
|
||||
async fn get_file_path(&self, id: &str) -> Result<StoragePath, DomainError>;
|
||||
@@ -317,7 +313,6 @@ pub trait FilePathResolutionPort: Send + Sync + 'static {
|
||||
}
|
||||
|
||||
/// Secondary port for file/directory existence verification
|
||||
#[async_trait]
|
||||
pub trait StorageVerificationPort: Send + Sync + 'static {
|
||||
/// Checks whether a file exists at the given path
|
||||
async fn file_exists(&self, storage_path: &StoragePath) -> Result<bool, DomainError>;
|
||||
@@ -327,14 +322,12 @@ pub trait StorageVerificationPort: Send + Sync + 'static {
|
||||
}
|
||||
|
||||
/// Secondary port for directory management
|
||||
#[async_trait]
|
||||
pub trait DirectoryManagementPort: Send + Sync + 'static {
|
||||
/// Creates directories if they do not exist
|
||||
async fn ensure_directory(&self, storage_path: &StoragePath) -> Result<(), DomainError>;
|
||||
}
|
||||
|
||||
/// Secondary port for storage usage management
|
||||
#[async_trait]
|
||||
pub trait StorageUsagePort: Send + Sync + 'static {
|
||||
/// Updates storage usage statistics for a user
|
||||
async fn update_user_storage_usage(&self, user_id: &str) -> Result<i64, DomainError>;
|
||||
@@ -362,7 +355,6 @@ pub trait StorageUsagePort: Send + Sync + 'static {
|
||||
}
|
||||
|
||||
/// Generic storage service interface for calendar and contact services
|
||||
#[async_trait]
|
||||
pub trait StorageUseCase: Send + Sync + 'static {
|
||||
/// Handle a request with the specified action and parameters
|
||||
async fn handle_request(&self, action: &str, params: Value) -> Result<Value, DomainError>;
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
//! image processing implementations.
|
||||
|
||||
use crate::common::errors::DomainError;
|
||||
use async_trait::async_trait;
|
||||
use bytes::Bytes;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
@@ -63,7 +62,6 @@ pub struct ThumbnailStatsDto {
|
||||
/// Implementations handle the actual image processing, caching,
|
||||
/// and storage of thumbnails, while the application layer only
|
||||
/// interacts through this abstraction.
|
||||
#[async_trait]
|
||||
pub trait ThumbnailPort: Send + Sync + 'static {
|
||||
/// Check if a file is an image that can have thumbnails.
|
||||
fn is_supported_image(&self, mime_type: &str) -> bool;
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
//! independent of specific image processing implementations.
|
||||
|
||||
use crate::common::errors::DomainError;
|
||||
use async_trait::async_trait;
|
||||
use bytes::Bytes;
|
||||
|
||||
/// Supported output formats for image transcoding.
|
||||
@@ -74,7 +73,6 @@ pub struct TranscodeStatsDto {
|
||||
/// Implementations handle the actual image conversion, caching,
|
||||
/// and format detection, while the application layer only interacts
|
||||
/// through this abstraction.
|
||||
#[async_trait]
|
||||
pub trait ImageTranscodePort: Send + Sync + 'static {
|
||||
/// Check if a MIME type can be transcoded.
|
||||
fn can_transcode(&self, mime_type: &str) -> bool;
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
use async_trait::async_trait;
|
||||
|
||||
use crate::application::dtos::trash_dto::TrashedItemDto;
|
||||
use crate::common::errors::Result;
|
||||
|
||||
/// Port for trash-related use cases
|
||||
#[async_trait]
|
||||
pub trait TrashUseCase: Send + Sync {
|
||||
/// List items in the user's trash
|
||||
async fn get_trash_items(&self, user_id: &str) -> Result<Vec<TrashedItemDto>>;
|
||||
|
||||
@@ -5,14 +5,12 @@
|
||||
//! implementation details.
|
||||
|
||||
use crate::common::errors::DomainError;
|
||||
use async_trait::async_trait;
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
/// Port for ZIP archive operations.
|
||||
///
|
||||
/// Implementations handle the actual ZIP file creation, compression,
|
||||
/// and recursive folder traversal.
|
||||
#[async_trait]
|
||||
pub trait ZipPort: Send + Sync + 'static {
|
||||
/// Create a ZIP archive containing the contents of a folder (recursively).
|
||||
///
|
||||
|
||||
Reference in New Issue
Block a user