rust: simplify derive macro usage

This commit is contained in:
Laszlo Nagy
2025-12-13 00:37:52 +11:00
parent cc022c77b5
commit 56bcc0caab
9 changed files with 36 additions and 37 deletions

View File

@@ -71,11 +71,11 @@ pub use types::*;
pub use validation::Validator; pub use validation::Validator;
mod types { mod types {
use serde::{Deserialize, Serialize}; use serde::Deserialize;
use std::path::PathBuf; use std::path::PathBuf;
/// Represents the application configuration with flattened structure. /// Represents the application configuration with flattened structure.
#[derive(Debug, PartialEq, Deserialize, Serialize)] #[derive(Debug, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct Main { pub struct Main {
#[serde(deserialize_with = "validate_schema_version")] #[serde(deserialize_with = "validate_schema_version")]
pub schema: String, pub schema: String,
@@ -105,7 +105,7 @@ mod types {
} }
/// Simplified intercept configuration with mode and directory. /// Simplified intercept configuration with mode and directory.
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[derive(Debug, PartialEq, serde::Deserialize, serde::Serialize)]
#[serde(tag = "mode")] #[serde(tag = "mode")]
pub enum Intercept { pub enum Intercept {
#[serde(rename = "wrapper")] #[serde(rename = "wrapper")]
@@ -147,7 +147,7 @@ mod types {
} }
/// Represents compiler configuration matching the YAML format. /// Represents compiler configuration matching the YAML format.
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[derive(Debug, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct Compiler { pub struct Compiler {
pub path: PathBuf, pub path: PathBuf,
#[serde(rename = "as", skip_serializing_if = "Option::is_none")] #[serde(rename = "as", skip_serializing_if = "Option::is_none")]
@@ -157,7 +157,7 @@ mod types {
} }
/// Compiler types that we can recognize and configure /// Compiler types that we can recognize and configure
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "lowercase")] #[serde(rename_all = "lowercase")]
pub enum CompilerType { pub enum CompilerType {
#[serde(alias = "gcc", alias = "gnu")] #[serde(alias = "gcc", alias = "gnu")]
@@ -186,7 +186,7 @@ mod types {
} }
/// Action to take for files matching a directory rule /// Action to take for files matching a directory rule
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] #[derive(Copy, Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "lowercase")] #[serde(rename_all = "lowercase")]
pub enum DirectoryAction { pub enum DirectoryAction {
Include, Include,
@@ -194,7 +194,7 @@ mod types {
} }
/// A rule that specifies how to handle files within a directory /// A rule that specifies how to handle files within a directory
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] #[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct DirectoryRule { pub struct DirectoryRule {
pub path: PathBuf, pub path: PathBuf,
pub action: DirectoryAction, pub action: DirectoryAction,
@@ -217,7 +217,7 @@ mod types {
/// ///
/// **Important**: For matching to work correctly, rule paths should use the same format as /// **Important**: For matching to work correctly, rule paths should use the same format as
/// configured in `format.paths.file`. This consistency is the user's responsibility. /// configured in `format.paths.file`. This consistency is the user's responsibility.
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct SourceFilter { pub struct SourceFilter {
#[serde(default = "default_enabled")] #[serde(default = "default_enabled")]
pub only_existing_files: bool, pub only_existing_files: bool,
@@ -235,7 +235,7 @@ mod types {
} }
/// Duplicate filter configuration matching the YAML format. /// Duplicate filter configuration matching the YAML format.
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct DuplicateFilter { pub struct DuplicateFilter {
pub match_on: Vec<OutputFields>, pub match_on: Vec<OutputFields>,
} }
@@ -249,7 +249,7 @@ mod types {
} }
/// Represent the fields of the JSON compilation database record. /// Represent the fields of the JSON compilation database record.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)] #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, serde::Deserialize, serde::Serialize)]
pub enum OutputFields { pub enum OutputFields {
#[serde(rename = "directory")] #[serde(rename = "directory")]
Directory, Directory,
@@ -264,7 +264,7 @@ mod types {
} }
/// Format configuration matching the YAML format. /// Format configuration matching the YAML format.
#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Default, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct Format { pub struct Format {
#[serde(default)] #[serde(default)]
pub paths: PathFormat, pub paths: PathFormat,
@@ -273,7 +273,7 @@ mod types {
} }
/// Format configuration of paths in the JSON compilation database. /// Format configuration of paths in the JSON compilation database.
#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Default, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct PathFormat { pub struct PathFormat {
#[serde(default)] #[serde(default)]
pub directory: PathResolver, pub directory: PathResolver,
@@ -282,7 +282,7 @@ mod types {
} }
/// Path resolver options matching the YAML format. /// Path resolver options matching the YAML format.
#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)] #[derive(Copy, Clone, Debug, Default, PartialEq, serde::Deserialize, serde::Serialize)]
pub enum PathResolver { pub enum PathResolver {
/// Leave the path as is without any transformation. (Default) /// Leave the path as is without any transformation. (Default)
#[default] #[default]
@@ -300,7 +300,7 @@ mod types {
} }
/// Configuration for formatting output entries matching the YAML format. /// Configuration for formatting output entries matching the YAML format.
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct EntryFormat { pub struct EntryFormat {
#[serde(default = "default_enabled")] #[serde(default = "default_enabled")]
pub use_array_format: bool, pub use_array_format: bool,

View File

@@ -12,7 +12,7 @@ use super::Entry;
use crate::config; use crate::config;
use thiserror::Error; use thiserror::Error;
#[derive(Clone, Debug)] #[derive(Debug)]
pub struct DuplicateEntryFilter { pub struct DuplicateEntryFilter {
/// The fields to use for filtering duplicate entries. /// The fields to use for filtering duplicate entries.
fields: Vec<config::OutputFields>, fields: Vec<config::OutputFields>,
@@ -67,7 +67,7 @@ impl TryFrom<config::DuplicateFilter> for DuplicateEntryFilter {
let mut already_seen = HashSet::new(); let mut already_seen = HashSet::new();
for field in &config.match_on { for field in &config.match_on {
if !already_seen.insert(field) { if !already_seen.insert(field) {
return Err(ConfigurationError::DuplicateField(field.clone())); return Err(ConfigurationError::DuplicateField(*field));
} }
} }

View File

@@ -39,7 +39,7 @@ use thiserror::Error;
/// A filter that determines which compilation database entries should be included /// A filter that determines which compilation database entries should be included
/// based on source file paths and directory-based rules. /// based on source file paths and directory-based rules.
#[derive(Clone, Debug)] #[derive(Debug)]
pub struct SourceEntryFilter { pub struct SourceEntryFilter {
/// The source filter configuration containing directory rules. /// The source filter configuration containing directory rules.
config: SourceFilter, config: SourceFilter,

View File

@@ -16,7 +16,6 @@ mod filter_duplicates;
mod filter_sources; mod filter_sources;
mod format; mod format;
use serde::{Deserialize, Serialize};
use shell_words; use shell_words;
use std::path; use std::path;
use thiserror::Error; use thiserror::Error;
@@ -28,7 +27,7 @@ pub use filter_sources::{SourceEntryFilter, SourceFilterError};
pub use format::{ConfigurablePathFormatter, FormatConfigurationError, FormatError, PathFormatter}; pub use format::{ConfigurablePathFormatter, FormatConfigurationError, FormatError, PathFormatter};
/// Represents an entry of the compilation database. /// Represents an entry of the compilation database.
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] #[derive(Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct Entry { pub struct Entry {
/// The main translation unit source processed by this compilation step. /// The main translation unit source processed by this compilation step.
/// This is used by tools as the key into the compilation database. /// This is used by tools as the key into the compilation database.
@@ -175,7 +174,7 @@ mod tests {
assert!(entry.command.is_empty()); assert!(entry.command.is_empty());
assert!(!entry.arguments.is_empty()); assert!(!entry.arguments.is_empty());
assert!(entry.clone().validate().is_ok()); assert!(entry.validate().is_ok());
} }
#[test] #[test]
@@ -185,7 +184,7 @@ mod tests {
assert!(!entry.command.is_empty()); assert!(!entry.command.is_empty());
assert!(entry.arguments.is_empty()); assert!(entry.arguments.is_empty());
assert!(entry.clone().validate().is_ok()); assert!(entry.validate().is_ok());
} }
#[test] #[test]

View File

@@ -50,9 +50,9 @@ impl TryFrom<(&args::BuildSemantic, &config::Main)> for OutputWriter {
let temp_path = &args.path.with_extension("tmp"); let temp_path = &args.path.with_extension("tmp");
let base_writer = ClangOutputWriter::create(temp_path)?; let base_writer = ClangOutputWriter::create(temp_path)?;
let unique_writer = UniqueOutputWriter::create(base_writer, &config.duplicates)?; let unique_writer = UniqueOutputWriter::create(base_writer, config.duplicates.clone())?;
let source_filter_writer = let source_filter_writer =
SourceFilterOutputWriter::create(unique_writer, &config.sources)?; SourceFilterOutputWriter::create(unique_writer, config.sources.clone())?;
let atomic_writer = let atomic_writer =
AtomicClangOutputWriter::new(source_filter_writer, temp_path, final_path); AtomicClangOutputWriter::new(source_filter_writer, temp_path, final_path);
let append_writer = AppendClangOutputWriter::new(atomic_writer, final_path, args.append); let append_writer = AppendClangOutputWriter::new(atomic_writer, final_path, args.append);

View File

@@ -144,9 +144,9 @@ pub(super) struct UniqueOutputWriter<T: IteratorWriter<clang::Entry>> {
impl<T: IteratorWriter<clang::Entry>> UniqueOutputWriter<T> { impl<T: IteratorWriter<clang::Entry>> UniqueOutputWriter<T> {
pub(super) fn create( pub(super) fn create(
writer: T, writer: T,
config: &config::DuplicateFilter, config: config::DuplicateFilter,
) -> Result<Self, WriterCreationError> { ) -> Result<Self, WriterCreationError> {
let filter = clang::DuplicateEntryFilter::try_from(config.clone()) let filter = clang::DuplicateEntryFilter::try_from(config)
.map_err(|err| WriterCreationError::Configuration(err.to_string()))?; .map_err(|err| WriterCreationError::Configuration(err.to_string()))?;
Ok(Self { writer, filter }) Ok(Self { writer, filter })
@@ -155,7 +155,7 @@ impl<T: IteratorWriter<clang::Entry>> UniqueOutputWriter<T> {
impl<T: IteratorWriter<clang::Entry>> IteratorWriter<clang::Entry> for UniqueOutputWriter<T> { impl<T: IteratorWriter<clang::Entry>> IteratorWriter<clang::Entry> for UniqueOutputWriter<T> {
fn write(self, entries: impl Iterator<Item = clang::Entry>) -> Result<(), WriterError> { fn write(self, entries: impl Iterator<Item = clang::Entry>) -> Result<(), WriterError> {
let mut filter = self.filter.clone(); let mut filter = self.filter;
let filtered_entries = entries.filter(move |entry| filter.unique(entry)); let filtered_entries = entries.filter(move |entry| filter.unique(entry));
self.writer.write(filtered_entries) self.writer.write(filtered_entries)
@@ -175,9 +175,9 @@ pub(super) struct SourceFilterOutputWriter<T: IteratorWriter<clang::Entry>> {
impl<T: IteratorWriter<clang::Entry>> SourceFilterOutputWriter<T> { impl<T: IteratorWriter<clang::Entry>> SourceFilterOutputWriter<T> {
pub(super) fn create( pub(super) fn create(
writer: T, writer: T,
config: &config::SourceFilter, config: config::SourceFilter,
) -> Result<Self, WriterCreationError> { ) -> Result<Self, WriterCreationError> {
let filter = clang::SourceEntryFilter::try_from(config.clone()) let filter = clang::SourceEntryFilter::try_from(config)
.map_err(|err| WriterCreationError::Configuration(err.to_string()))?; .map_err(|err| WriterCreationError::Configuration(err.to_string()))?;
Ok(Self { writer, filter }) Ok(Self { writer, filter })
@@ -335,7 +335,7 @@ mod tests {
], ],
}; };
let writer = SourceFilterOutputWriter::create(MockWriter, &config).unwrap(); let writer = SourceFilterOutputWriter::create(MockWriter, config).unwrap();
let entries = vec![ let entries = vec![
clang::Entry::from_arguments_str("src/main.c", vec!["gcc", "-c"], "/project", None), clang::Entry::from_arguments_str("src/main.c", vec!["gcc", "-c"], "/project", None),
@@ -360,7 +360,7 @@ mod tests {
directories: vec![], directories: vec![],
}; };
let writer = SourceFilterOutputWriter::create(MockWriter, &config).unwrap(); let writer = SourceFilterOutputWriter::create(MockWriter, config).unwrap();
let entries = vec![clang::Entry::from_arguments_str( let entries = vec![clang::Entry::from_arguments_str(
"any/file.c", "any/file.c",
@@ -392,7 +392,7 @@ mod tests {
], ],
}; };
let writer = SourceFilterOutputWriter::create(MockWriter, &config).unwrap(); let writer = SourceFilterOutputWriter::create(MockWriter, config).unwrap();
let entries = vec![ let entries = vec![
clang::Entry::from_arguments_str("./src/main.c", vec!["gcc", "-c"], "/project", None), clang::Entry::from_arguments_str("./src/main.c", vec!["gcc", "-c"], "/project", None),
@@ -435,9 +435,9 @@ mod tests {
// Build the writer pipeline: base -> unique -> source_filter // Build the writer pipeline: base -> unique -> source_filter
let base_writer = ClangOutputWriter::create(&output_path).unwrap(); let base_writer = ClangOutputWriter::create(&output_path).unwrap();
let unique_writer = UniqueOutputWriter::create(base_writer, &duplicate_config).unwrap(); let unique_writer = UniqueOutputWriter::create(base_writer, duplicate_config).unwrap();
let source_filter_writer = let source_filter_writer =
SourceFilterOutputWriter::create(unique_writer, &source_config).unwrap(); SourceFilterOutputWriter::create(unique_writer, source_config).unwrap();
// Test entries: some should be filtered, some should pass through // Test entries: some should be filtered, some should pass through
let entries = vec![ let entries = vec![

View File

@@ -36,7 +36,7 @@ impl OtherArguments {
impl Arguments for OtherArguments { impl Arguments for OtherArguments {
fn kind(&self) -> ArgumentKind { fn kind(&self) -> ArgumentKind {
self.kind.clone() self.kind
} }
fn as_arguments(&self, _path_updater: &dyn Fn(&Path) -> Cow<Path>) -> Vec<String> { fn as_arguments(&self, _path_updater: &dyn Fn(&Path) -> Cow<Path>) -> Vec<String> {

View File

@@ -123,7 +123,7 @@ pub trait Arguments: std::fmt::Debug {
/// - `Output`: An output file or related argument (e.g., `-o output.o`). /// - `Output`: An output file or related argument (e.g., `-o output.o`).
/// - `Other`: Any other argument not classified above (e.g., compiler switches like `-Wall`). /// - `Other`: Any other argument not classified above (e.g., compiler switches like `-Wall`).
/// Can optionally specify which compiler pass the argument affects. /// Can optionally specify which compiler pass the argument affects.
#[derive(Debug, Clone, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub enum ArgumentKind { pub enum ArgumentKind {
Compiler, Compiler,
Source, Source,
@@ -132,7 +132,7 @@ pub enum ArgumentKind {
} }
/// Represents different compiler passes that an argument might affect. /// Represents different compiler passes that an argument might affect.
#[derive(Debug, Clone, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub enum CompilerPass { pub enum CompilerPass {
Info, Info,
Preprocessing, Preprocessing,

View File

@@ -27,7 +27,7 @@ impl TestArguments {
impl Arguments for TestArguments { impl Arguments for TestArguments {
fn kind(&self) -> ArgumentKind { fn kind(&self) -> ArgumentKind {
self.kind.clone() self.kind
} }
fn as_arguments(&self, _path_updater: &dyn Fn(&Path) -> Cow<Path>) -> Vec<String> { fn as_arguments(&self, _path_updater: &dyn Fn(&Path) -> Cow<Path>) -> Vec<String> {