serdeio 0.5.0

Tiny IO utility library for Rust to serialize/deserialize Serde compatible structs
Documentation
# SerdeIO - Agent Guide

This guide helps agentic coding agents work effectively with the SerdeIO Rust library.

## Project Overview

SerdeIO is a tiny IO utility library for Rust that provides serialization/deserialization of Serde-compatible structs across multiple data formats (JSON, JSON Lines, CSV, YAML).

## Build/Test Commands

### Essential Commands
```bash
# Build and check the project
cargo check

# Run all tests
cargo test

# Run a specific test
cargo test <test_name> --lib
# Examples:
cargo test test_data_format --lib
cargo test test_read --lib

# Format code
cargo fmt

# Check with Clippy (linting)
cargo clippy -- -D warnings

# Build examples
cargo build --examples

# Run example with arguments
cargo run --example json2jsonl -- <input_file>
```

### Testing Strategy
- Unit tests are embedded within modules using `#[cfg(test)] mod test { ... }`
- Tests use `std::io::Cursor` for in-memory testing of read/write operations
- Test data is typically defined as string literals with `r#"...""#` syntax
- Tests verify both successful operations and error conditions

## Code Style Guidelines

### Import Organization
- Group imports: std libraries first, then external crates, then internal modules
- Use `use` statements at the top of files, organized by scope
- Prefer specific imports over glob imports
- Example import order:
```rust
use std::{fs::File, io::{Read, Write}, path::Path};

use serde::{de::DeserializeOwned, Serialize};
use thiserror::Error;

use crate::{backend, types::DataFormat, Error};
```

### Naming Conventions
- **Functions**: snake_case (e.g., `read_record_from_file`)
- **Types & Enums**: PascalCase (e.g., `DataFormat`)
- **Constants**: SCREAMING_SNAKE_CASE (rare in this codebase)
- **Variables**: snake_case (e.g., `data_format`, `reader`)
- **Modules**: snake_case (e.g., `jsonlines`, `backend`)

### Error Handling
- Use dedicated `Error` enum with `thiserror` for structured error types
- Error variants include `DataFormat`, `UnsupportedFormat`, `Io`, `Json`, `Csv`, `Yaml`
- Use `?` operator for error propagation through `#[from]` derives
- Specific error messages defined in error variants

### Type System
- Use generic type parameters with trait bounds: `T: DeserializeOwned`, `T: Serialize`
- Prefer `impl Trait` over concrete types in function parameters for flexibility
- Use lifetime parameters where needed: `'a` for iterator bounds
- Result types: `Result<T, crate::Error>` for operations that can fail

### Module Structure
- `pub(crate)` for internal modules that are not part of public API
- Public API re-exports in `lib.rs`
- Backend modules feature-gated: `#[cfg(feature = "csv")]`
- Consistent structure across backend modules (read/write functions + tests)

### Code Organization Patterns
- Backend modules follow a consistent pattern:
  - `read<T: DeserializeOwned>(reader) -> Result<T>` for single records
  - `read<T: DeserializeOwned>(reader) -> Result<Vec<T>>` for multiple records
  - `write<T: Serialize>(writer, record) -> Result<()>` for single records
  - `write<'a, T: Serialize + 'a>(writer, records) -> Result<()>` for multiple records

### Formatting and Style
- Use `rustfmt` for code formatting (configured in .vscode/settings.json)
- Line length follows rustfmt defaults
- Use 4-space indentation (rustfmt standard)
- Prefer `to_owned()` or `to_string()` over `clone()` for string conversions

### Feature Flags
- Optional backends are feature-gated: `#[cfg(feature = "csv")]`, `#[cfg(feature = "yaml")]`
- Always test both with and without features enabled
- Conditional compilation for format-specific code paths

### Documentation
- Use `///` for public API documentation
- Include examples in documentation where helpful
- Use `#[doc = include_str!("../README.md")]` for crate-level documentation

### Testing Patterns
- Test functions named descriptively: `test_read`, `test_write`, `test_data_format`
- Use `Cursor<Vec<u8>>` for testing write operations
- Use `Cursor<&str>` for testing read operations
- Test data structures include necessary derives: `Debug, Deserialize, Serialize, PartialEq, Eq`
- Assertions use `assert_eq!()` for comparing expected vs actual results

### Performance Considerations
- Use `BufReader` and `BufWriter` for I/O operations
- Avoid unnecessary allocations in hot paths
- Prefer iterator-based solutions over manual loops where appropriate
- Use `IntoIterator` bounds for flexible input types in write functions

## Development Workflow
1. Always run `cargo check` after changes
2. Run `cargo clippy` and fix all warnings
3. Run `cargo fmt` before committing
4. Run `cargo test` to verify functionality
5. Test with different feature combinations if applicable

## Common Pitfalls to Avoid
- Don't use unwrap() in library code - prefer proper error handling
- Don't forget to feature-gate optional dependencies
- Don't ignore clippy warnings - they often indicate real issues
- Don't forget to include test cases for error conditions