# Peta::FFI::Cairo::Path
📦 std
`Cairo::Path` package plug-in - the tied-array live view onto `cairo_path_t*`.
`Cairo::Path` is not a plain blessed pointer like the other cairo objects:
it is a **tied ARRAY of tied HASHes of tied ARRAYs** presenting a live view
onto a C `cairo_path_t*`. This file is a 1:1 mirror of upstream
`CairoPath.xs`; read that alongside this for the semantics. The four
Perl-visible packages map to the XS’s four MODULE blocks:
- `Cairo::Path` (tied ARRAY) - one element per path command.
- `Cairo::Path::Data` (tied HASH) - keys ”type“ / ”points“ for a command.
- `Cairo::Path::Points`(tied ARRAY) - the points of one command.
- `Cairo::Path::Point` (tied 2-ARRAY)- the (x, y) of one point.
## Magic representation (mirrors `create_tie` / `cairo_perl_mg_get`)
`create_tie` (XS lines 41-69) attaches TWO magics to the referent AV/HV:
1. `PERL_MAGIC_tied` (»P«, obj = the blessed RV) so Perl routes element
access through this package’s FETCH/STORE/… methods.
2. `PERL_MAGIC_ext` (»~«, mg_ptr = the C object pointer, namlen = 0),
with `mg->mg_private = MY_MAGIC_SIG (0xCAFE)` marking it as ours.
The C pointer carried in the ext slot IS the element/point offset: the
top-level tie carries `cairo_path_t*`; each `Cairo::Path::Data` /
`::Points` tie carries the `cairo_path_data_t*` pointing at that command’s
header; each `Cairo::Path::Point` tie carries the `cairo_path_data_t*`
pointing at that specific point union. There is no separate index stored -
the pointer already threads the location, exactly as the XS does (e.g.
`newSVCairoPathPoint(&data[index + 1])`, XS line 427/444).
Recovery mirrors `cairo_perl_mg_get` (XS lines 29-37): given the invocant
blessed RV `sv`, walk `SvRV(sv)`«s magic chain for a `PERL_MAGIC_ext` slot
whose `mg_private == 0xCAFE`, and read `mg_ptr`.
## VERSION SCOPE
Path is stable cairo API; there is no version gating and no post-1.109
superset here.
## Functions
### Other Functions
#### `path_destroy`
`$path->DESTROY` -> cairo_path_destroy (XS:283-295). Recover the pointer through the ext-magic slot (via `mg_get`, matching `SvCairoPath`); if present, destroy it. The 5.6.x mg_ptr-unset branch is not mirrored (pperl targets 5.42+, XS lines 289-293 are guarded out).
#### `path_fetchsize`
`Cairo::Path::FETCHSIZE` (XS:297-305): number of path commands. Walk data[] stepping by `header.length`, counting each command.
#### `path_fetch`
`Cairo::Path::FETCH` (XS:307-320): the i-th command as a tied `Cairo::Path::Data`. Walk by header.length, counting to `index`; return the tie carrying that command’s `cairo_path_data_t*`, else undef.
#### `data_fetch`
`Cairo::Path::Data::FETCH` (XS:337-351): key ”type“ -> nickname; ”points“ -> a tied `Cairo::Path::Points`; anything else croaks.
#### `data_store`
`Cairo::Path::Data::STORE` (XS:353-367): only ”points“ is writable. Rewrite this command’s coordinates from the arrayref value (keeping the existing header.type), and return a fresh tied Points view (matching the XS RETVAL).
#### `data_exists`
`Cairo::Path::Data::EXISTS` (XS:369-379): true for ”type“/“points“ only.
#### `data_firstkey`
`Cairo::Path::Data::FIRSTKEY` (XS:381-385): always ”type“.
#### `data_nextkey`
`Cairo::Path::Data::NEXTKEY` (XS:387-395): ”type“ -> ”points“, else undef.
#### `points_fetchsize`
`Cairo::Path::Points::FETCHSIZE` (XS:412-419): n_points for this command.
#### `points_fetch`
`Cairo::Path::Points::FETCH` (XS:421-432): the i-th point of this command as a tied `Cairo::Path::Point` carrying `&data[index + 1]`, else undef.
#### `points_store`
`Cairo::Path::Points::STORE` (XS:434-454): write x/y of the i-th point back into the C buffer from the [x,y] arrayref value; return a tied Point view.
#### `point_fetchsize`
`Cairo::Path::Point::FETCHSIZE` (XS:471-475): always 2.
#### `point_fetch`
`Cairo::Path::Point::FETCH` (XS:477-494): index 0 -> x, 1 -> y, read straight from the C buffer’s point union; else undef.
#### `point_store`
`Cairo::Path::Point::STORE` (XS:496-513): the LIVE write-back. index 0 sets point.x, 1 sets point.y - straight into the C buffer - and returns the new value as an NV (matching `newSVnv(data->point.x = value)`).