# 05 - 类与数据布局

Viper 中的 `class` 有两种用途：定义**数据布局**（结构体/联合体/枚举，本章内容），以及定义**面向对象的对象类型**（见 [06-oop.md](06-oop.md)）。

## 结构体定义

普通 `class` 定义编译为 LLVM 结构体类型：

```python
class point:
    x: t.CInt
    y: t.CInt
```

在 C 中：
```c
struct point {
    int x;
    int y;
};
```

在 LLVM IR 中：
```llvm
%"<SHA1>.point" = type { i32, i32 }
```

### 带属性的结构体

```python
@c.Attribute(t.attr.packed)
class idt_entry:
    base_low:    t.CUInt16T
    selector:    t.CUInt16T
    ist_attr:    t.CUInt8T
    type_attr:   t.CUInt8T
    base_middle: t.CUInt16T
    base_high:   t.CUInt32T
    reserved1:   t.CUInt32T
```

### 结构体数组

```python
idt: list[idt_entry, 256] = []
```

### 结构体指针成员

```python
class node:
    value: t.CInt
    next: node | t.CPtr          # 指向自身的指针（有向图链表）
```

### 结构体实例化与初始化

```python
entry: idt_entry = idt_entry()
```

或带构造函数：

```python
mousepoint = Point(x=1, y=2)
```

乱序传参或带参传参对于结构体的初始化同样有效：

```python
entry: idt_entry = idt_entry(selector=0x08, base_low=0x0000)
```

也可以给结构体成员指定默认值：

```python
class config:
    width: t.CInt = 640
    height: t.CInt = 480
    depth: t.CInt = 32
```

使用 `c.Addr` 获取实例指针：

```python
obj_ptr: MyClass | t.CPtr = c.Addr(MyClass(arg1, arg2))
```

### 匿名结构体成员（❌）

> WARNING: **警告：** 由于 Viper 在声明结构体，枚举等处不需要关键字，因此 `t.Anonymouse` 是不需要使用的。此关键字不再维护，强行使用可能导致未定义行为。

继承 `t.Anonymous` 的类作为匿名成员嵌入：

```python
class header(t.Anonymous):
    magic: t.CUInt32T
    version: t.CUInt32T

class packet:
    header          # 匿名嵌入，可直接访问 packet.magic
    length: t.CUInt32T
```

### 字节序标记

> WARNING: **警告：** 此关键字是实验性的。未经充分测试，不当使用可能导致未定义行为。

使用 `t.BigEndian` 或 `t.LittleEndian` 标记成员的字节序：

```python
class network_packet:
    length: t.CUInt16T | t.BigEndian     # 大端序存储
    type: t.CUInt8T                       # 默认小端序
```

## 联合体

继承 `t.CUnion` 定义联合体：

```python
class value(t.CUnion):
    ival: t.CInt
    fval: t.CFloat
    pval: t.CVoid | t.CPtr
```

等价 C 代码：
```c
union value {
    int ival;
    float fval;
    void* pval;
};
```

## 枚举

继承 `t.CEnum` 定义枚举：

```python
class color(t.CEnum):
    RED:   t.CEnum = 0
    GREEN: t.CEnum = 1
    BLUE:  t.CEnum = 2
```

等价 C 代码：
```c
enum color {
    RED = 0,
    GREEN = 1,
    BLUE = 2
};
```

枚举成员可直接使用名称：

```python
c: t.CInt = color.RED
```

## REnum（标签联合体）

`t.CEnum` 是普通枚举（整数常量集合），`t.REnum` 是**标签联合体**（tagged union / Rust enum 风格）。每个变体可携带不同的 payload，通过 `match` 模式匹配分派。

### 适用场景

| 类型 | 变体数 | 通用字段 | 访问模式 | 适用 |
|------|--------|---------|---------|------|
| `t.CEnum` | 任意 | 无 | 整数比较 | 状态码、opcode、token 类型 |
| `t.REnum` | 少（~10） | 无 | match 分派 | 类型系统、AST 少变体场景 |
| 胖节点（如 AST） | 多（70+） | 有 | vtype + 直接属性 | AST 节点（见 [includes/ast](../includes/ast)） |

### 定义

```python
class LLVMType(t.REnum):
    class Int:               # 变体 Int，携带 payload
        Bits: t.CInt

    class Ptr:               # 变体 Ptr，携带 payload
        Pointee: LLVMType | t.CPtr   # 自引用用指针

    class Void:              # 变体 Void，无 payload
        pass
```

布局为 `{ i32 __tag, <max_variant_payload> }`，所有变体共享最大变体的 payload 空间。

### match 分派

```python
match ty:
    case LLVMType.Int:        # 位置绑定 payload：ty.Bits 可用
        snprintf(buf, size, "i%d", ty.IntBits)
    case LLVMType.Ptr:        # ty.PtrPointee 可用
        TypePrint(buf, size, ty.PtrPointee)
    case LLVMType.Void:
        string.strcpy(buf, "void")
```

详见 [includes/llvmlite/__types.py](../includes/llvmlite/__types.py) 的 `LLVMType` 实现。

## Typedef

使用 `t.CTypedef` 创建类型别名：

```python
irq_handler_t: t.CTypedef | t.Callable[[], t.CInt]   # typedef int (*irq_handler_t)();
```

或通过注解赋值：

```python
MyStruct: t.CTypedef = original_struct   # typedef struct original_struct MyStruct;
```

更推荐通过后者的形式，前者编译器不一定能够识别到注解是对 `t.CTypedef` 的，还是后面的注解的，而且容易触发未定义行为。

## 泛型类（PEP 695 语法）

TransPyC 支持 PEP 695 泛型语法 `class Name[T]:`，定义类型参数化的类。

### 基本泛型类

```python
@t.NoVTable
class GSListNode[T]:
    Next: T | t.CPtr

@t.NoVTable
class GSList[T]:
    Head: T | t.CPtr
    Tail: T | t.CPtr
    Count: t.CSizeT
    def append(self, node: T): ...
```

### 递归泛型继承

泛型类可递归引用自身作为类型参数，实现强类型自引用结构（无需转型）：

```python
@t.NoVTable
class GNode(GSListNode[GNode]):    # 递归泛型继承
    value: t.CInt
# 此时 GNode.Next: GNode|CPtr —— 强类型，零转型
```

这是 C（`void*` + cast）、C++（模板继承但无 `@t.NoVTable` 精细控制）、Rust（无继承，需 trait bound）均无法如此简洁表达的能力。

### 实例化

```python
lst: GSList[GNode] | t.CPtr = GSList[GNode]()
node: GNode | t.CPtr = GNode()
lst.append(node)    # 类型安全：append 只接受 GNode
```

详见 [includes/linkedlist.py](../includes/linkedlist.py) 和 [includes/vector.py](../includes/vector.py)。

## 位域

使用 `t.Bit(n)` 定义位域成员：

```python
class flags:
    a: t.CUInt32T | t.Bit[1]
    b: t.CUInt32T | t.Bit[3]
    c: t.CUInt32T | t.Bit[4]
```

注意：如果存入超出位域宽度的值，会被截断。例如 `a` 为 1 位，存入 2（二进制 `10`）会被截断为 0。
