> ## Documentation Index
> Fetch the complete documentation index at: https://docs.arkffi.hmbill.cn/llms.txt
> Use this file to discover all available pages before exploring further.

# Struct

> Define and manipulate C structs in ArkTS

`Struct` defines the memory layout of a C struct, supporting serialization/deserialization. It works with `ffi.ptr` to pass data to C functions.

## Example

```typescript theme={null}
import { Struct, FFIType, ffi } from 'arkffi';

const Point = Struct({
  x: FFIType.int32,
  y: FFIType.int32,
});

const buf = Point.create({ x: 10, y: 20 });
const ptr = ffi.ptr(buf);

const read = Point.fromPtr(somePtr);
console.log(read.x, read.y);
```

## Struct()

```typescript theme={null}
function Struct(fields: Record<string, string | StructSchema>): StructSchema;
```

| Parameter | Type                                     | Description                                       |
| --------- | ---------------------------------------- | ------------------------------------------------- |
| `fields`  | `Record<string, string \| StructSchema>` | Field name to type code mapping, supports nesting |

## StructSchema

### `size`

```typescript theme={null}
readonly size: number;
```

Total size of the struct in bytes, including padding.

### `create()`

```typescript theme={null}
create(obj: Record<string, number | bigint | ArrayBuffer>): ArrayBuffer;
```

Serialize an object to an ArrayBuffer. Nested struct fields accept the ArrayBuffer from their own `create()`.

### `fromPtr()`

```typescript theme={null}
fromPtr(ptr: number, byteOffset?: number): Record<string, number>;
```

Read struct data from a raw pointer. **Primitive fields return numbers; nested struct fields return a pointer** (the absolute address of the sub-struct). Use the inner schema's `fromPtr` to read further.

### `get()` / `set()`

```typescript theme={null}
get(buf: ArrayBuffer, field: string): number;
set(buf: ArrayBuffer, field: string, value: number): void;
```

Only supported for primitive fields. Nested struct fields return `0` / no-op.

## Nested Structs

Field values can be another `StructSchema` for recursive layout computation.

```typescript theme={null}
// C: struct Inner { double x, y; };
// C: struct Outer { struct Inner pos; const char* name; };
const Inner = Struct({
  x: FFIType.double,
  y: FFIType.double,
});
const Outer = Struct({
  pos: Inner,
  name: FFIType.ptr,
});

let buf = Outer.create({
  pos: Inner.create({ x: 1.0, y: 2.0 }),
  name: 0x1234,
});

let r = Outer.fromPtr(ptr);
let innerR = Inner.fromPtr(r.pos);
console.log(innerR.x, innerR.y); // 1.0, 2.0
```

## With `dlopen` (HFA register passing)

For small HFA structs passed in registers, pass `StructSchema` directly as `args` / `returns` to `dlopen`:

```typescript theme={null}
// C: complex_t complex_add(complex_t a, complex_t b);
const Complex = Struct({ real: FFIType.double, imag: FFIType.double });
const lib = dlopen(LIB_NAME, {
  complex_add: { args: [Complex, Complex], returns: Complex },
});

let a = Complex.create({ real: 1, imag: 2 });
let b = Complex.create({ real: 3, imag: 4 });
let ptr: number = lib.symbols.complex_add(a, b);
let result = Complex.fromPtr(ptr); // { real: 4, imag: 6 }
```

Struct args are expanded to their field values for register passing. Struct returns allocate a buffer and return its pointer. Read the result synchronously via `fromPtr`.

## ARM64 Alignment Rules

| Type Code | C Type                     | Size | Align |
| --------- | -------------------------- | ---- | ----- |
| `c`       | `char` / `int8_t`          | 1    | 1     |
| `i`       | `int32_t` / `int`          | 4    | 4     |
| `l`       | `int64_t` / `uint64_t`     | 8    | 8     |
| `d`       | `double`                   | 8    | 8     |
| `f`       | `float`                    | 4    | 4     |
| `b`       | `bool`                     | 1    | 1     |
| `s`       | `const char*` (pointer)    | 8    | 8     |
| `p` / `k` | `void*` / function pointer | 8    | 8     |

Nested struct alignment is the maximum alignment of all its fields.

```typescript theme={null}
const Mixed = Struct({ a: 'c', b: 'i', c: 'c' });
// a at offset 0 (1 byte), b at offset 4 (3 pad), c at offset 8 (1 byte)
// total = 12 bytes
```

## Working with C Functions

```typescript theme={null}
// C: void setPoint(struct Point* p, int x, int y)

const Point = Struct({ x: 'i', y: 'i' });
const lib = dlopen('lib.so', {
  setPoint: { args: [FFIType.ptr, FFIType.int32, FFIType.int32], returns: 'i' },
});

const buf = Point.create({ x: 0, y: 0 });
lib.symbols.setPoint(ffi.ptr(buf), 42, 99);

const result = Point.fromPtr(ffi.ptr(buf));
console.log(result.x, result.y);
```
