# photokit

Safe Rust bindings for Apple's [Photos](https://developer.apple.com/documentation/photos) framework on macOS.

> **Status:** v0.3.0 adds the Tier-1 `async_api` module on top of the fully audited Photos.framework surface, with executor-agnostic futures for authorization, `performChanges`, image requests, and live-photo editing callbacks.

## Quick start

```rust,no_run
use photokit::prelude::*;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let library = PHPhotoLibrary::shared()?;
    println!("status: {:?}", PHPhotoLibrary::authorization_status());

    let assets = PHAsset::fetch(&PHFetchOptions::default())?;
    println!("assets: {}", assets.len());

    if let Some(asset) = assets.first() {
        let manager = PHImageManager::shared()?;
        let request = manager.request_image_data(
            asset,
            &PHImageRequest::new(320.0, 240.0, PHImageContentMode::AspectFit),
        )?;
        let image = request.wait(10_000)?;
        println!("image bytes: {}", image.data().len());
    }

    let _ = library.fetch_asset_collections(&PHFetchOptions::default())?;
    Ok(())
}
```

## Async API

Enable the `async` feature to access non-blocking wrappers for Photos.framework completion-handler APIs:

```toml
[dependencies]
photokit = { version = "0.3", features = ["async"] }
```

```rust
use photokit::async_api::AsyncPHPhotoLibrary;
use photokit::PHAccessLevel;

# async fn demo() -> Result<(), Box<dyn std::error::Error>> {
let status = AsyncPHPhotoLibrary::request_authorization(PHAccessLevel::ReadWrite).await?;
# Ok(())
# }
```

All async types implement `std::future::Future` and are executor-agnostic.
See [`async_api`](src/async_api.rs) for the full API surface.

## Highlights

- `PHPhotoLibrary` authorization helpers plus summary/detailed change observers, availability observers, and persistent-change history helpers.
- `PHAsset`, `PHCollection`, `PHAssetCollection`, and `PHCollectionList` fetch helpers with typed subtype/source/resource wrappers.
- `PHChangeRequest` builders for asset, album, folder, and project mutation flows.
- `PHImageManager` / `PHCachingImageManager` request handles for images, image data, live photos, video requests, and caching.
- `PHAssetResourceManager` transfer helpers for reading or writing asset resources.
- `PHContentEditingInput` / `PHContentEditingOutput` plus `PHLivePhotoEditingContext` for non-destructive editing workflows.
- `PHCloudIdentifier` batch lookup helpers and richer Photos-specific error metadata.

## Coverage audit

See [`COVERAGE.md`](COVERAGE.md) for the framework audit, implemented rows, partial rows, and deferred macOS-unavailable or deprecated APIs.

## Examples

The crate ships with numbered examples covering every logical area:

- `01_photokit_smoke`
- `02_phasset_fetch`
- `03_phasset_collection_fetch`
- `04_phcollection_list_fetch`
- `05_phphoto_library_authorization`
- `06_phimage_manager_requests`
- `07_phfetch_result_methods`
- `08_phchange_observer`
- `09_phcontent_editing_input`
- `10_phcontent_editing_output`
- `11_phobject_change_details`
- `12_phfetch_options_builder`
- `13_phasset_creation_request`
- `14_phlive_photo`
- `15_phcloud_identifier`
- `16_async_api` *(requires `--features async`)*

Run them with:

```bash
for ex in examples/*.rs; do
  name="$(basename "$ex" .rs)"
  if [ "$name" = "16_async_api" ]; then
    cargo run --example "$name" --features async
  else
    cargo run --example "$name"
  fi
done
```

## Verification

```bash
cargo clippy --all-features --all-targets -- -D warnings
cargo test --all-features
for ex in examples/*.rs; do
  name="$(basename "$ex" .rs)"
  if [ "$name" = "16_async_api" ]; then
    cargo run --example "$name" --features async
  else
    cargo run --example "$name"
  fi
done
```

## License

Licensed under either of [Apache-2.0](LICENSE-APACHE) or [MIT](LICENSE-MIT) at your option.
