libredwg-sys 0.1.0

Raw FFI bindings to the LibreDWG C sources (vendored, unmodified upstream), built natively via cc + bindgen (no Emscripten/WASM).
Documentation
//! Raw FFI bindings to the LibreDWG C sources (vendored, unmodified, from
//! the real upstream project at `lib/libredwg`, GPLv3+; see
//! docs/THIRD_PARTY_NOTICES.md).
//! Generated by `build.rs` via `bindgen` against the public
//! `dwg.h`/`dwg_api.h` headers plus this crate's own `uncad_write_dxf_file`
//! shim (see `shim/uncad_shim.h`).
//!
//! This crate is intentionally low-level and `unsafe`-heavy -- it exists to
//! be wrapped by the `uncad` crate, not used directly.
//!
//! # Not thread-safe -- callers must serialize every call themselves
//!
//! The underlying LibreDWG C library has non-reentrant global state (e.g.
//! the `loglevel` global read/written throughout `decode.c`/`bits.c`, and
//! likely more that hasn't been individually catalogued). Calling into any
//! function in this crate concurrently from multiple threads -- even two
//! calls that never touch the same `Dwg_Data`/`Dwg_Object` -- has
//! reproducibly caused `STATUS_HEAP_CORRUPTION` once both threads' work
//! overlapped enough for the shared C-side state to race. **This crate does
//! nothing to prevent that**; every FFI entry point here is exactly as
//! unsynchronized as the C library it binds.
//!
//! The `uncad` crate's own public API (`uncad::parse()` and friends) is
//! safe to call from multiple threads because it serializes every call
//! through a single process-wide `Mutex` before reaching this crate --
//! see `uncad`'s top-level doc comment / `docs/ARCHITECTURE.md`'s "Thread
//! safety" section. Any other consumer of `libredwg-sys` directly must
//! implement that same serialization itself (a single global lock around
//! every call into this crate, held for the call's entire duration) or
//! risk memory corruption under concurrent use.

#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(dead_code)]
// bindgen emits `mem::transmute(x)` for every bitfield accessor regardless
// of whether the source and target types happen to coincide (they do for
// every current `BITCODE_B`/`_BS`-backed bitfield in dwg.h) -- harmless,
// and not something editing generated code (re-generated fresh on every
// build) could fix. See docs/CAVEATS.md's "cargo clippy 현재 상태" note.
#![allow(clippy::useless_transmute)]
// Same rationale, for bindgen's generated `BindgenUninitializedField` helper
// (`as_slice`/`as_mut_slice`/`as_ref`/`as_mut`) -- its `unsafe fn`s have no
// `# Safety` doc section because bindgen doesn't emit one, not because this
// crate's own unsafe code is undocumented (see `dynapi.rs` in `uncad` for
// this project's own actual safety-doc convention).
#![allow(clippy::missing_safety_doc)]
// Same rationale again: bindgen's generated helper methods call other
// unsafe functions (`slice::from_raw_parts`, `mem::transmute`) without
// wrapping each one in its own `unsafe { }` block, relying on the whole
// `unsafe fn` body being implicitly unsafe (2021 edition default) --
// harmless and, again, not this crate's own code to restyle.
#![allow(unsafe_op_in_unsafe_fn)]

include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

// --- Hand-defined HATCH sub-structs -----------------------------------
//
// bindgen can't generate real field access for these two (same struct-
// codegen limitation as Dwg_Object -- see build.rs's blocklist_type calls
// for the full explanation), but this project needs real field access
// into them (HATCH boundary-path geometry isn't reachable through dynapi
// at all -- dynapi only exposes top-level entity fields by name, not
// nested struct internals). Hand-defined here to match dwg.h's field
// order and types exactly; #[repr(C)] then reproduces C's own alignment/
// padding rules automatically; the layout_test() functions below assert
// the resulting sizes against clang's own authoritative sizeof() (56/200/
// 32 bytes -- the same numbers bindgen's own layout_tests() asserted
// against before these types were blocklisted) as a safety net against a
// transcription mistake in this hand-written mirror.

/// `_dwg_HATCH_ControlPoint` (dwg.h) -- a SPLINE-type boundary edge's
/// control point.
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct Dwg_HATCH_ControlPoint {
    pub parent: *mut std::ffi::c_void,
    pub point: BITCODE_2RD,
    pub weight: BITCODE_BD,
}

/// `_dwg_HATCH_PathSeg` (dwg.h) -- one edge of a non-polyline HATCH
/// boundary path. Not a real C union (despite the "could be a union"
/// comment in dwg.h) -- every field is present regardless of
/// `curve_type`; only the fields relevant to that specific curve type are
/// meaningfully populated.
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct Dwg_HATCH_PathSeg {
    pub parent: *mut std::ffi::c_void,
    pub curve_type: BITCODE_RC,
    /* LINE */
    pub first_endpoint: BITCODE_2RD,
    pub second_endpoint: BITCODE_2RD,
    /* CIRCULAR ARC */
    pub center: BITCODE_2RD,
    pub radius: BITCODE_BD,
    pub start_angle: BITCODE_BD,
    pub end_angle: BITCODE_BD,
    pub is_ccw: BITCODE_B,
    /* ELLIPTICAL ARC */
    pub endpoint: BITCODE_2RD,
    pub minor_major_ratio: BITCODE_BD,
    /* SPLINE */
    pub degree: BITCODE_BL,
    pub is_rational: BITCODE_B,
    pub is_periodic: BITCODE_B,
    pub num_knots: BITCODE_BL,
    pub num_control_points: BITCODE_BL,
    pub knots: *mut BITCODE_BD,
    pub control_points: *mut Dwg_HATCH_ControlPoint,
    pub num_fitpts: BITCODE_BL,
    pub fitpts: *mut BITCODE_2RD,
    pub start_tangent: BITCODE_2RD,
    pub end_tangent: BITCODE_2RD,
}

/// `_dwg_HATCH_Path` (dwg.h) -- one HATCH boundary path, either a
/// polyline (`polyline_paths`, when `flag & 0x02`) or a list of curved/
/// straight edges (`segs`).
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct Dwg_HATCH_Path {
    pub parent: *mut std::ffi::c_void,
    pub flag: BITCODE_BL,
    pub num_segs_or_paths: BITCODE_BL,
    pub segs: *mut Dwg_HATCH_PathSeg,
    pub bulges_present: BITCODE_B,
    pub closed: BITCODE_B,
    pub polyline_paths: *mut Dwg_HATCH_PolylinePath,
    pub num_boundary_handles: BITCODE_BL,
    pub boundary_handles: *mut *mut Dwg_Object_Ref,
}

// _dwg_HATCH_PolylinePath (still bindgen-generated -- not blocklisted)
// references the raw tag name `_dwg_HATCH_Path` directly in its `parent`
// field, so this alias needs to exist even though nothing in this crate
// otherwise uses the tag name (only the `Dwg_HATCH_Path` typedef above).
pub type _dwg_HATCH_Path = Dwg_HATCH_Path;

/// `_dwg_HATCH_DefLine` (dwg.h) -- one pattern-fill "definition line": a
/// family of parallel lines (`angle`/`pt0`/`offset`, in the pattern's own
/// unscaled/unrotated definition space) plus an optional dash pattern
/// (`dashes`, positive = dash length, negative = gap length; empty means a
/// continuous line) -- one of `Dwg_Entity_HATCH.deflines`. Unlike
/// `Dwg_HATCH_Path`/`PathSeg`/`ControlPoint` above, this one *is* reachable
/// through dynapi (`num_deflines`/`deflines` are plain top-level
/// `Dwg_Entity_HATCH` fields, not nested inside a Path/PathSeg element) --
/// but it still has to be hand-defined and blocklisted the same way,
/// because allowlisting it directly forces bindgen to also generate a real
/// (non-opaque) `_dwg_entity_HATCH` for its `parent` field to point at
/// (nothing else in this crate ever allowlists `_dwg_entity_HATCH`; HATCH's
/// own fields are all read through dynapi's untyped `void*`), and
/// `_dwg_entity_HATCH` itself then hits the identical struct-codegen
/// failure. `parent` is left as an untyped `*mut c_void` here specifically
/// to avoid that cascade, matching the other three HATCH sub-structs' own
/// `parent` fields. `pt0`/`offset` are declared `BITCODE_2BD` in dwg.h, but
/// typed `BITCODE_2RD` here instead -- same interchangeable-once-decoded
/// reasoning as `Point2D`'s own doc comment (both are just 2 `double`s with
/// no padding); `BITCODE_2RD` is already a bound type elsewhere in this
/// crate (`Dwg_HATCH_PathSeg`), while nothing else pulls in the separate
/// `BITCODE_2BD` alias, so reusing it avoids introducing a type bindgen
/// would otherwise never generate.
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct Dwg_HATCH_DefLine {
    pub parent: *mut std::ffi::c_void,
    pub angle: BITCODE_BD,
    pub pt0: BITCODE_2RD,
    pub offset: BITCODE_2RD,
    pub num_dashes: BITCODE_BS,
    pub dashes: *mut BITCODE_BD,
}
pub type _dwg_HATCH_DefLine = Dwg_HATCH_DefLine;

/// `_dwg_HATCH_Color` (dwg.h) -- one gradient-fill color stop: `shift_value`
/// (0.0-1.0, this stop's position along the gradient) plus `color` (a plain
/// `Dwg_Color`, already a normally-bound type elsewhere in this crate --
/// e.g. entity/layer color -- so no further hand-writing needed for it).
/// One of `Dwg_Entity_HATCH.colors` (`num_colors`/`colors`). Same
/// `parent: struct _dwg_entity_HATCH *` cascade as `Dwg_HATCH_DefLine`
/// above (allowlisting it directly forces bindgen to also materialize a
/// real, cascade-failing `_dwg_entity_HATCH`), same fix: blocklisted and
/// hand-defined with `parent` left as an untyped `*mut c_void`. Verified
/// against clang's own authoritative `sizeof()` (64 bytes: parent@0,
/// shift_value@8, color@16) via the same allowlist-then-read-the-failing-
/// layout_tests()-assert technique used for the other hand-written HATCH
/// sub-structs.
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct Dwg_HATCH_Color {
    pub parent: *mut std::ffi::c_void,
    pub shift_value: BITCODE_BD,
    pub color: Dwg_Color,
}
pub type _dwg_HATCH_Color = Dwg_HATCH_Color;

/// `_dwg_MLINE_vertex` (dwg.h) -- same bindgen struct-codegen failure as
/// the HATCH types above, hand-defined the same way. Its `vertex`/
/// `vertex_direction`/`miter_direction` fields are declared `BITCODE_3BD`
/// in dwg.h, which bindgen never generates a binding for on its own (only
/// pulled in transitively by whatever references it, and nothing
/// currently allowlisted does) -- `dwg_point_3d` is used instead, since
/// `BITCODE_3BD`/`Dwg_Bitcode_3BD` is just 3 `double`s with no padding,
/// identically laid out. `lines` (the per-vertex parallel-line array,
/// `Dwg_MLINE_line*`) is declared as an opaque `*mut c_void` here rather
/// than a real pointer type -- nothing in this crate reads through it
/// (`uncad`'s MLINE rendering only uses `vertex`, the centerline point;
/// see docs/CAVEATS.md), and leaving it untyped avoids also needing to
/// bind/hand-write `Dwg_MLINE_line` just for a field no caller
/// dereferences.
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct Dwg_MLINE_vertex {
    pub parent: *mut std::ffi::c_void,
    pub vertex: dwg_point_3d,
    pub vertex_direction: dwg_point_3d,
    pub miter_direction: dwg_point_3d,
    pub num_lines: BITCODE_RC,
    pub lines: *mut std::ffi::c_void,
}

/// `_dwg_MLINESTYLE_line` (dwg.h) -- one parallel-line definition in an
/// MLINESTYLE OBJECT: `offset` (distance from the MLINE centerline,
/// combined with each MLINE vertex's own `miter_direction` to get that
/// line's actual point -- see `uncad`'s `convert::convert_mline` doc
/// comment) plus `color`/`lt_index`/`lt_ltype` (this project only reads
/// `offset`; the rest aren't used for rendering). Same
/// `parent: struct _dwg_object_MLINESTYLE *` cascade as the HATCH
/// sub-structs above (confirmed: allowlisting it alone produces a
/// `1usize - 112usize` layout_tests() assert on `_dwg_object_MLINESTYLE`).
/// Blocklisted and hand-defined instead, same recipe -- verified against
/// clang's real `sizeof()` (80 bytes: parent@0, offset@8, color@16,
/// lt_index@64, lt_ltype@72) the same way. `lt_ltype` (`BITCODE_H`, since
/// 2018) is a real `*mut Dwg_Object_Ref` here rather than an opaque
/// `c_void` pointer -- `Dwg_Object_Ref` is already a plain bound type
/// elsewhere in this crate, so there's no extra hand-writing needed to type
/// it correctly, unlike `Dwg_MLINE_vertex.lines` above.
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct Dwg_MLINESTYLE_line {
    pub parent: *mut std::ffi::c_void,
    pub offset: BITCODE_BD,
    pub color: Dwg_Color,
    pub lt_index: BITCODE_BSd,
    pub lt_ltype: *mut Dwg_Object_Ref,
}
pub type _dwg_MLINESTYLE_line = Dwg_MLINESTYLE_line;

#[allow(clippy::unnecessary_operation, clippy::identity_op)]
const _: () = {
    ["Size of Dwg_HATCH_ControlPoint"][std::mem::size_of::<Dwg_HATCH_ControlPoint>() - 32];
    ["Size of Dwg_HATCH_PathSeg"][std::mem::size_of::<Dwg_HATCH_PathSeg>() - 200];
    ["Size of Dwg_HATCH_Path"][std::mem::size_of::<Dwg_HATCH_Path>() - 56];
    ["Size of Dwg_HATCH_DefLine"][std::mem::size_of::<Dwg_HATCH_DefLine>() - 64];
    ["Size of Dwg_HATCH_Color"][std::mem::size_of::<Dwg_HATCH_Color>() - 64];
    ["Size of Dwg_MLINE_vertex"][std::mem::size_of::<Dwg_MLINE_vertex>() - 96];
    ["Size of Dwg_MLINESTYLE_line"][std::mem::size_of::<Dwg_MLINESTYLE_line>() - 80];
};