---
description: API design principles and patterns for skia-rs
globs: ["**/*.rs"]
alwaysApply: false
---

# API Design Principles

## Skia API Compatibility

The primary goal is API compatibility with Skia. When implementing a feature:

1. **Reference the original**: Check `skia/` submodule for the C++ implementation
2. **Match signatures**: Function names and parameter order should match Skia
3. **Match semantics**: Behavior should be identical to Skia
4. **Document differences**: If Rust requires a different approach, document it

## Builder Pattern

Use builders for complex object construction:

```rust
pub struct PathBuilder {
    path: Path,
    last_move: Option<Point>,
}

impl PathBuilder {
    pub fn new() -> Self { ... }
    pub fn move_to(&mut self, x: Scalar, y: Scalar) -> &mut Self { ... }
    pub fn line_to(&mut self, x: Scalar, y: Scalar) -> &mut Self { ... }
    pub fn build(self) -> Path { ... }
}
```

## Method Chaining

Support fluent interfaces where appropriate:

```rust
impl Paint {
    pub fn set_color(&mut self, color: Color4f) -> &mut Self {
        self.color = color;
        self
    }

    pub fn set_style(&mut self, style: Style) -> &mut Self {
        self.style = style;
        self
    }
}

// Usage:
paint.set_color(Color4f::RED)
     .set_style(Style::Stroke)
     .set_stroke_width(2.0);
```

## Const Correctness

- Use `const fn` where possible
- Define common constants as associated constants

```rust
impl Rect {
    pub const EMPTY: Self = Self { left: 0.0, top: 0.0, right: 0.0, bottom: 0.0 };

    #[inline]
    pub const fn new(left: Scalar, top: Scalar, right: Scalar, bottom: Scalar) -> Self {
        Self { left, top, right, bottom }
    }
}
```

## Common Patterns

### Cloning vs Referencing

- Prefer references for read-only access
- Clone only when ownership transfer is needed
- Use `Cow<T>` when clone-on-write is beneficial

### Option Patterns

```rust
// Skia-style: return Option for fallible operations
pub fn invert(&self) -> Option<Matrix> {
    let det = self.determinant();
    if det == 0.0 {
        return None;
    }
    Some(self.compute_inverse(det))
}
```

### Iteration

```rust
// Provide iterators for collections
impl Path {
    pub fn iter(&self) -> PathIter<'_> {
        PathIter { path: self, index: 0 }
    }
}

// Make types iterable
impl<'a> IntoIterator for &'a Path {
    type Item = PathElement;
    type IntoIter = PathIter<'a>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}
```
