Phase 5: scaffold Crucible (sow-tools) — dispatcher + builder shims, container, PR-first CI, fail-closed (D11, D19).
This commit is contained in:
@@ -1,317 +0,0 @@
|
||||
package gff
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type jsonDocument struct {
|
||||
FileType string `json:"file_type"`
|
||||
FileVersion string `json:"file_version"`
|
||||
Root jsonStruct `json:"root"`
|
||||
}
|
||||
|
||||
type jsonStruct struct {
|
||||
StructType uint32 `json:"struct_type"`
|
||||
Fields []jsonField `json:"fields"`
|
||||
}
|
||||
|
||||
type jsonField struct {
|
||||
Label string `json:"label"`
|
||||
Type string `json:"type"`
|
||||
Value json.RawMessage `json:"value"`
|
||||
}
|
||||
|
||||
type jsonLocString struct {
|
||||
StringRef uint32 `json:"string_ref"`
|
||||
Entries []LocStringEntry `json:"entries"`
|
||||
}
|
||||
|
||||
func (s Struct) MarshalJSON() ([]byte, error) {
|
||||
payload, err := marshalStruct(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(payload)
|
||||
}
|
||||
|
||||
func (s *Struct) UnmarshalJSON(data []byte) error {
|
||||
var payload jsonStruct
|
||||
if err := json.Unmarshal(data, &payload); err != nil {
|
||||
return err
|
||||
}
|
||||
decoded, err := unmarshalStruct(payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*s = decoded
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d Document) MarshalJSON() ([]byte, error) {
|
||||
root, err := marshalStruct(d.Root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return json.Marshal(jsonDocument{
|
||||
FileType: d.FileType,
|
||||
FileVersion: d.FileVersion,
|
||||
Root: root,
|
||||
})
|
||||
}
|
||||
|
||||
func (d *Document) UnmarshalJSON(data []byte) error {
|
||||
var payload jsonDocument
|
||||
if err := json.Unmarshal(data, &payload); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
root, err := unmarshalStruct(payload.Root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.FileType = payload.FileType
|
||||
d.FileVersion = payload.FileVersion
|
||||
d.Root = root
|
||||
return nil
|
||||
}
|
||||
|
||||
func marshalStruct(in Struct) (jsonStruct, error) {
|
||||
fields := make([]jsonField, 0, len(in.Fields))
|
||||
for _, field := range in.Fields {
|
||||
payload, err := marshalValue(field.Value)
|
||||
if err != nil {
|
||||
return jsonStruct{}, fmt.Errorf("marshal field %q: %w", field.Label, err)
|
||||
}
|
||||
fields = append(fields, jsonField{
|
||||
Label: field.Label,
|
||||
Type: field.Type.String(),
|
||||
Value: payload,
|
||||
})
|
||||
}
|
||||
|
||||
return jsonStruct{
|
||||
StructType: in.Type,
|
||||
Fields: fields,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func unmarshalStruct(in jsonStruct) (Struct, error) {
|
||||
fields := make([]Field, 0, len(in.Fields))
|
||||
for _, field := range in.Fields {
|
||||
ft, err := parseFieldType(field.Type)
|
||||
if err != nil {
|
||||
return Struct{}, fmt.Errorf("field %q: %w", field.Label, err)
|
||||
}
|
||||
|
||||
value, err := unmarshalValue(ft, field.Value)
|
||||
if err != nil {
|
||||
return Struct{}, fmt.Errorf("field %q: %w", field.Label, err)
|
||||
}
|
||||
|
||||
fields = append(fields, Field{
|
||||
Label: field.Label,
|
||||
Type: ft,
|
||||
Value: value,
|
||||
})
|
||||
}
|
||||
|
||||
return Struct{
|
||||
Type: in.StructType,
|
||||
Fields: fields,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func marshalValue(value Value) (json.RawMessage, error) {
|
||||
switch typed := value.(type) {
|
||||
case ByteValue:
|
||||
return json.Marshal(uint8(typed))
|
||||
case CharValue:
|
||||
return json.Marshal(int8(typed))
|
||||
case WordValue:
|
||||
return json.Marshal(uint16(typed))
|
||||
case ShortValue:
|
||||
return json.Marshal(int16(typed))
|
||||
case DWordValue:
|
||||
return json.Marshal(uint32(typed))
|
||||
case IntValue:
|
||||
return json.Marshal(int32(typed))
|
||||
case DWord64Value:
|
||||
return json.Marshal(uint64(typed))
|
||||
case Int64Value:
|
||||
return json.Marshal(int64(typed))
|
||||
case FloatValue:
|
||||
return json.Marshal(float32(typed))
|
||||
case DoubleValue:
|
||||
return json.Marshal(float64(typed))
|
||||
case StringValue:
|
||||
return json.Marshal(string(typed))
|
||||
case ResRefValue:
|
||||
return json.Marshal(string(typed))
|
||||
case LocString:
|
||||
return json.Marshal(jsonLocString(typed))
|
||||
case VoidValue:
|
||||
return json.Marshal(base64.StdEncoding.EncodeToString([]byte(typed)))
|
||||
case Struct:
|
||||
payload, err := marshalStruct(typed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(payload)
|
||||
case ListValue:
|
||||
payload := make([]jsonStruct, 0, len(typed))
|
||||
for _, item := range typed {
|
||||
entry, err := marshalStruct(item)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
payload = append(payload, entry)
|
||||
}
|
||||
return json.Marshal(payload)
|
||||
case Orientation:
|
||||
return json.Marshal(typed)
|
||||
case Vector:
|
||||
return json.Marshal(typed)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported value type %T", value)
|
||||
}
|
||||
}
|
||||
|
||||
func unmarshalValue(ft FieldType, data []byte) (Value, error) {
|
||||
switch ft {
|
||||
case TypeByte:
|
||||
var out uint8
|
||||
if err := json.Unmarshal(data, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ByteValue(out), nil
|
||||
case TypeChar:
|
||||
var out int8
|
||||
if err := json.Unmarshal(data, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return CharValue(out), nil
|
||||
case TypeWord:
|
||||
var out uint16
|
||||
if err := json.Unmarshal(data, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return WordValue(out), nil
|
||||
case TypeShort:
|
||||
var out int16
|
||||
if err := json.Unmarshal(data, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ShortValue(out), nil
|
||||
case TypeDWord:
|
||||
var out uint32
|
||||
if err := json.Unmarshal(data, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return DWordValue(out), nil
|
||||
case TypeInt:
|
||||
var out int32
|
||||
if err := json.Unmarshal(data, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return IntValue(out), nil
|
||||
case TypeDWord64:
|
||||
var out uint64
|
||||
if err := json.Unmarshal(data, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return DWord64Value(out), nil
|
||||
case TypeInt64:
|
||||
var out int64
|
||||
if err := json.Unmarshal(data, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return Int64Value(out), nil
|
||||
case TypeFloat:
|
||||
var out float32
|
||||
if err := json.Unmarshal(data, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return FloatValue(out), nil
|
||||
case TypeDouble:
|
||||
var out float64
|
||||
if err := json.Unmarshal(data, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return DoubleValue(out), nil
|
||||
case TypeCExoString:
|
||||
var out string
|
||||
if err := json.Unmarshal(data, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return StringValue(out), nil
|
||||
case TypeResRef:
|
||||
var out string
|
||||
if err := json.Unmarshal(data, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ResRefValue(out), nil
|
||||
case TypeCExoLocString:
|
||||
var out jsonLocString
|
||||
if err := json.Unmarshal(data, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return LocString(out), nil
|
||||
case TypeVoid:
|
||||
var out string
|
||||
if err := json.Unmarshal(data, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
decoded, err := base64.StdEncoding.DecodeString(out)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decode base64 void: %w", err)
|
||||
}
|
||||
return VoidValue(decoded), nil
|
||||
case TypeStruct:
|
||||
var payload jsonStruct
|
||||
if err := json.Unmarshal(data, &payload); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return unmarshalStruct(payload)
|
||||
case TypeList:
|
||||
var payload []jsonStruct
|
||||
if err := json.Unmarshal(data, &payload); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := make(ListValue, 0, len(payload))
|
||||
for _, item := range payload {
|
||||
decoded, err := unmarshalStruct(item)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, decoded)
|
||||
}
|
||||
return out, nil
|
||||
case TypeOrientation:
|
||||
var out Orientation
|
||||
if err := json.Unmarshal(data, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
case TypeVector:
|
||||
var out Vector
|
||||
if err := json.Unmarshal(data, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported field type %d", ft)
|
||||
}
|
||||
}
|
||||
|
||||
func parseFieldType(name string) (FieldType, error) {
|
||||
for kind, candidate := range fieldTypeNames {
|
||||
if candidate == name {
|
||||
return kind, nil
|
||||
}
|
||||
}
|
||||
return 0, fmt.Errorf("unknown field type %q", name)
|
||||
}
|
||||
Reference in New Issue
Block a user