yamime 0.1.0

Complete Rust port of Go's mime package with async-first design
Documentation
# yamime

[![Crates.io](https://img.shields.io/crates/v/yamime.svg)](https://crates.io/crates/yamime)
[![Documentation](https://docs.rs/yamime/badge.svg)](https://docs.rs/yamime)
[![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)](LICENSE)
[![Build Status](https://img.shields.io/github/workflow/status/async-php/yamime/CI)](https://github.com/async-php/yamime/actions)

> Complete Rust port of Go's `mime` package with async-first design

A comprehensive MIME handling library for Rust, providing full support for MIME type detection, media type parsing, multipart messages, quoted-printable encoding, and RFC 2047 encoded-words. Built with async/await and tokio for modern Rust applications.

## Features

- ๐ŸŽฏ **MIME Type Detection** - File extension to MIME type mapping with 1000+ built-in types
- ๐Ÿ“ **Media Type Parsing** - RFC 2045/2616/2231 compliant media type handling
- ๐Ÿ“ฎ **Multipart Messages** - Full multipart/form-data and multipart/mixed support
- ๐Ÿ”ค **Encoded Words** - RFC 2047 encoded-word encoding/decoding for email headers
- โœ‰๏ธ **Quoted-Printable** - RFC 2045 quoted-printable encoding/decoding
- โšก **Async First** - Built on tokio for high-performance async I/O
- ๐Ÿฆ€ **Pure Rust** - No unsafe code, fully type-safe
- ๐Ÿงช **Well Tested** - 121+ tests with 73.78% code coverage

## Installation

Add this to your `Cargo.toml`:

```toml
[dependencies]
yamime = "0.1.0"
tokio = { version = "1", features = ["full"] }
```

## Quick Start

### MIME Type Detection

```rust
use yamime::type_by_extension;

// Get MIME type by file extension
let mime_type = type_by_extension(".html");
assert_eq!(mime_type, Some("text/html; charset=utf-8".to_string()));

let mime_type = type_by_extension(".jpg");
assert_eq!(mime_type, Some("image/jpeg".to_string()));
```

### Media Type Parsing

```rust
use yamime::parse_media_type;

let (media_type, params) = parse_media_type("text/html; charset=utf-8").unwrap();
assert_eq!(media_type, "text/html");
assert_eq!(params.get("charset"), Some(&"utf-8".to_string()));
```

### Multipart Form Data

```rust
use yamime::multipart::Writer;
use tokio::io::AsyncWriteExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut output = Vec::new();
    let mut writer = Writer::new(&mut output);

    // Add a text field
    writer.write_field("username", "john_doe").await?;

    // Add a file
    let mut file_writer = writer.create_form_file("avatar", "photo.jpg").await?;
    file_writer.write_all(b"image data here").await?;

    writer.close().await?;

    println!("Multipart data created: {} bytes", output.len());
    Ok(())
}
```

### Reading Multipart Data

```rust
use yamime::multipart::Reader;
use tokio::io::AsyncReadExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let data = b"--boundary\r\n\
Content-Disposition: form-data; name=\"field\"\r\n\
\r\n\
value\r\n\
--boundary--\r\n";

    let mut reader = Reader::new(&data[..], "boundary");

    while let Some(mut part) = reader.next_part().await? {
        println!("Field name: {:?}", part.form_name());

        let mut content = String::new();
        part.read_to_string(&mut content).await?;
        println!("Content: {}", content);
    }

    Ok(())
}
```

### Quoted-Printable Encoding

```rust
use yamime::quotedprintable::Writer;
use tokio::io::AsyncWriteExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut output = Vec::new();
    let mut writer = Writer::new(&mut output);

    writer.write_all(b"Hello, World! Special chars: =").await?;
    writer.close().await?;

    println!("Encoded: {}", String::from_utf8_lossy(&output));
    // Output: "Hello, World! Special chars: =3D"

    Ok(())
}
```

### Encoded Words (Email Headers)

```rust
use yamime::{WordEncoder, WordDecoder};

// Encoding
let encoder = WordEncoder::QEncoding;
let encoded = encoder.encode("UTF-8", "Hello, ไธ–็•Œ!");
println!("Encoded: {}", encoded);
// Output: =?UTF-8?q?Hello,_=E4=B8=96=E7=95=8C!?=

// Decoding
let decoder = WordDecoder::new();
let decoded = decoder.decode(&encoded).unwrap();
assert_eq!(decoded, "Hello, ไธ–็•Œ!");
```

## API Overview

### Core Modules

- **`mime_type`** - MIME type detection and extension mapping
- **`media_type`** - Media type parsing and formatting (RFC 2045/2616/2231)
- **`multipart`** - Multipart message handling (RFC 2046/2388)
  - `Reader` - Parse multipart messages
  - `Writer` - Create multipart messages
  - `Form` - Multipart form data support
- **`quotedprintable`** - Quoted-printable encoding (RFC 2045)
  - `Reader` - Decode quoted-printable
  - `Writer` - Encode quoted-printable
- **`encoded_word`** - RFC 2047 encoded-word support
  - `WordEncoder` - Encode headers
  - `WordDecoder` - Decode headers
- **`error`** - Error types and result definitions

### Platform Support

The library includes platform-specific MIME type loading:
- **Unix/Linux/macOS** - Loads from `/etc/mime.types` and other standard locations
- **Windows** - Reads from Windows Registry

## Performance

The library includes comprehensive benchmarks using Criterion:

```bash
cargo bench
```

Example benchmark results:
- Media type parsing: ~125 ns per operation
- Quoted-printable encoding (1KB): ~45 ยตs (22 MiB/s)
- Multipart writing (5 parts): ~150 ยตs

## Testing

### Run Tests

```bash
# All tests (121+ tests)
cargo test

# Unit tests only
cargo test --lib

# Integration tests
cargo test --test integration_tests

# With coverage
cargo tarpaulin --out Html
```

### Test Coverage

Current test coverage: **73.78%** (695/942 lines)

- โœ… **error.rs**: 100%
- โœ… **mime_type.rs**: 97%
- โœ… **encoded_word.rs**: ~88%
- โœ… **quotedprintable/writer.rs**: ~85%
- โœ… **multipart/writer.rs**: 81%

See [TESTING_GUIDE.md](TESTING_GUIDE.md) for detailed testing documentation.

### Fuzzing

The project includes fuzz tests using cargo-fuzz:

```bash
# Install cargo-fuzz
cargo install cargo-fuzz

# Run fuzzing (examples)
cargo fuzz run fuzz_parse_media_type -- -max_total_time=60
cargo fuzz run fuzz_multipart_reader -- -max_total_time=60
cargo fuzz run fuzz_encoded_word -- -max_total_time=60
cargo fuzz run fuzz_quoted_printable -- -max_total_time=60
```

## Examples

See the `examples/` directory for more complete examples:

- **`basic_mime_type.rs`** - MIME type detection
- **`multipart_form.rs`** - Creating multipart forms
- **`email_headers.rs`** - Encoding email headers
- **`file_upload.rs`** - Handling file uploads

Run examples:

```bash
cargo run --example basic_mime_type
```

## Comparison with Other Libraries

| Feature | yamime | mime | mailparse |
|---------|---------|------|-----------|
| MIME type detection | โœ… | โŒ | โŒ |
| Media type parsing | โœ… | โœ… | โœ… |
| Multipart messages | โœ… | โŒ | โœ… |
| Quoted-printable | โœ… | โŒ | โœ… |
| Encoded words (RFC 2047) | โœ… | โŒ | โœ… |
| Async/await | โœ… | โŒ | โŒ |
| Form data | โœ… | โŒ | โŒ |
| Writing support | โœ… | โŒ | โŒ |

## Requirements

- **Rust**: 1.70 or later
- **Tokio**: 1.35 or later (async runtime)

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

### Development Setup

```bash
# Clone the repository
git clone https://github.com/async-php/yamime.git
cd yamime

# Run tests
cargo test

# Run benchmarks
cargo bench

# Check formatting
cargo fmt --check

# Run clippy
cargo clippy -- -D warnings
```

### Guidelines

1. Write tests for new features
2. Maintain or improve code coverage
3. Follow Rust naming conventions
4. Add documentation for public APIs
5. Run `cargo fmt` before committing

## License

This project is dual-licensed under:

- MIT License ([LICENSE-MIT]LICENSE-MIT or http://opensource.org/licenses/MIT)
- Apache License, Version 2.0 ([LICENSE-APACHE]LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)

at your option.

## Acknowledgments

- Inspired by Go's `mime` package
- Built with [tokio]https://tokio.rs/ async runtime
- Tested with [Criterion]https://github.com/bheisler/criterion.rs benchmark framework
- Fuzzed with [cargo-fuzz]https://github.com/rust-fuzz/cargo-fuzz

## Resources

- [Documentation]https://docs.rs/yamime
- [Crates.io]https://crates.io/crates/yamime
- [Repository]https://github.com/async-php/yamime
- [Issue Tracker]https://github.com/async-php/yamime/issues
- [Author]https://github.com/hackmasker

### RFCs Implemented

- [RFC 2045]https://tools.ietf.org/html/rfc2045 - MIME Part One: Format of Internet Message Bodies
- [RFC 2046]https://tools.ietf.org/html/rfc2046 - MIME Part Two: Media Types
- [RFC 2047]https://tools.ietf.org/html/rfc2047 - MIME Part Three: Message Header Extensions
- [RFC 2231]https://tools.ietf.org/html/rfc2231 - MIME Parameter Value and Encoded Word Extensions
- [RFC 2388]https://tools.ietf.org/html/rfc2388 - Returning Values from Forms: multipart/form-data
- [RFC 2616]https://tools.ietf.org/html/rfc2616 - HTTP/1.1 (Media Type handling)

---

**Made with โค๏ธ in Rust**