Known limitations ================= rustfits aims for parity with astropy and fitsio on the modern FITS feature set, but a handful of edge cases aren't yet implemented (or are deliberately out of scope). This page lists them and shows the workaround where one exists. Each item is tagged: * **(not yet)** — on the roadmap; will land when prioritized or when a user prompts for it. File an issue if you hit one. * **(by design)** — deliberately not supported; the workaround is the recommended path. Tables ------ * **TNULL masking on VLA columns** *(not yet)* — ``mask_null=True`` works for fixed B/I/J/K columns but raises on VLA columns with a TNULL card in the header. Read with ``mask_null=False`` and apply the mask yourself for now. * **Variable-length columns with TDIMn** *(not yet)* — TDIMn on a P/Q column would reshape each heap cell to the declared dims, useful for VLA-of-images, but with a quirk: the spec only allows ONE variable axis per cell, so fully variable ``(n, m)`` shapes aren't expressible in FITS without padding. * **``TDISPn`` on write** *(by design)* — the display-format hint isn't emitted by rustfits's writers. Add it by hand via ``header["TDISP1"] = ...`` if you need it; it's informational per the spec. Images ------ The image surface (read, slice, write, ``extend``, ``__setitem__``, BLANK / MaskedArray, BSCALE/BZERO, unsigned-int trick) is feature-complete for both uncompressed and tile-compressed HDUs. One narrow gap: * **Per-tile ZBLANK column** *(not yet)* — header-level ZBLANK on compressed integer images is supported. The convention also allows a per-tile *column*-form ZBLANK; rustfits doesn't read it. Rare in practice — cfitsio typically emits the header form even for DITHER_2. General ------- * **Multithreaded throughput (GIL release)** *(not yet)* — rustfits releases the GIL only during remote (``http`` / ``ftp``) downloads. The heavy CPU paths — tile decode/encode, large chunked I/O, checksum — currently hold it, so several Python threads calling into rustfits serialize on those. Single-threaded use is unaffected (the common case). Releasing the GIL around the pure-Rust decode/encode spans is a targeted future change, gated on a real multithreaded workload — file an issue if you have one. * **Random groups** (``GROUPS=T``, ``PTYPEn``) *(by design)* — legacy format; vanishingly rare in new files. Not on the roadmap. Files and compression --------------------- * **Whole-file gzip is read-only** *(not yet)* — a ``.gz`` path is decompressed into memory on open, so reads work, but ``r+`` / ``w+`` on a ``.gz`` raise. Write-back (recompress-on-close) isn't implemented. More to the point, **prefer per-HDU compression over whole-file compression**. Tile-compressed images (the ``compress=...`` argument to ``create_image_hdu`` / ``write_image``) and compressed tables (``compress=...`` on ``create_table_hdu`` / ``write_table``) generally beat a whole-file ``.gz`` on every axis that matters: - **Storage** — the tile-compression conventions apply the codec suited to the data (RICE / HCOMPRESS / GZIP with byte-shuffle, optional float quantization), so they typically compress tighter than gzipping the raw byte stream. - **Memory** — a ``.gz`` must be decompressed *in full* into RAM before any byte is readable (gzip isn't seekable; FITS needs random access). Tile compression decodes only the tiles you touch, keeping peak memory near the size of your slice rather than the whole image or table. - **Speed** — partial and scattered reads pull only the needed tiles (and the per-tile cache makes repeated access cheap), whereas whole-file gzip pays the full-decompress cost up front on every open. To write a compressed file, write a plain ``.fits`` and choose tile/HDU compression per HDU — see the compression sections of the image and table guides. Cross-tool interop caveats -------------------------- These aren't rustfits limitations per se — they're points where the FITS ecosystem disagrees and rustfits picks one side. * **astropy ``1PX(N)`` parser** — astropy 7.2.0 rejects bit- packed VLA columns (``1PX``/``1QX``) with ``VerifyError`` during column setup. rustfits writes spec-conforming ``1PX(maxbits)`` headers, but astropy can't currently read them; fitsio (built on cfitsio) reads them fine. See the pinning test ``test_astropy_pxqx_documented_limitation``. * **astropy ``CompImageHDU`` verify_checksum** — astropy's ``verify_checksum`` for compressed HDUs has its own internal bug (TypeError on ``_compute_checksum(None)``) that triggers on its own writes too. rustfits's self-verify is correct; we don't cross-verify ZHECKSUM against astropy. * **i8 (``TLONGLONG``) RICE compression** — cfitsio's encoder doesn't support 64-bit RICE; fitsio refuses the write. rustfits rejects ``compress=Rice1()`` + i8 dtype upfront and points at ``compress=Gzip2(...)`` instead. Files we wrote with i64 RICE would be unreadable everywhere except rustfits.