# 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)`).