[READ-ONLY] Mirror of https://github.com/bombshell-dev/tty. Platform independent 2D layout engine for terminal applications based on Clay
0

Configure Feed

Select the types of activity you want to include in your feed.

tty / typedef.ts
3.0 kB 150 lines
1export type Attrs<T> = { 2 [K in keyof T]: TypeDef<T[K]>; 3}; 4 5export type Alignment = 1 | 2 | 4 | 8; 6 7export type LayoutElement<T> = { 8 type: "padding"; 9 byteLength: number; 10} | { 11 type: "field"; 12 name: string; 13 offset: number; 14 typedef: Attrs<T>[keyof Attrs<T>]; 15}; 16 17export type Struct<T> = { 18 type: "struct"; 19 byteLength: number; 20 byteAlign: Alignment; 21 layout: LayoutElement<T>[]; 22}; 23 24export type Num<T> = { 25 type: 26 | "i32" 27 | "f32" 28 | "f64" 29 | "uint8" 30 | "uint16" 31 | "uint32" 32 | "int16" 33 | "int32"; 34 byteAlign: Alignment; 35 byteLength: number; 36 T?: T; 37}; 38 39export type Arr<T> = { 40 type: "array"; 41 element: TypeDef<T>; 42 length: number; 43 byteLength: number; 44 byteAlign: Alignment; 45}; 46 47export type TypeDef<T> = Num<T> | Struct<T> | Arr<T>; 48 49export function array<T>(element: TypeDef<T>, length: number): Arr<T[]> { 50 return { 51 type: "array", 52 element: element as TypeDef<T[]>, 53 length, 54 byteLength: element.byteLength * length, 55 byteAlign: element.byteAlign, 56 }; 57} 58 59export const f32 = (): TypeDef<number> => ({ 60 type: "f32", 61 byteLength: 4, 62 byteAlign: 4, 63}); 64export const int32 = (): TypeDef<number> => ({ 65 type: "int32", 66 byteLength: 4, 67 byteAlign: 4, 68}); 69export const uint8 = (): TypeDef<number> => ({ 70 type: "uint8", 71 byteLength: 1, 72 byteAlign: 1, 73}); 74export const uint16 = (): TypeDef<number> => ({ 75 type: "uint16", 76 byteLength: 2, 77 byteAlign: 2, 78}); 79export const uint32 = (): TypeDef<number> => ({ 80 type: "uint32", 81 byteAlign: 4, 82 byteLength: 4, 83}); 84 85export function struct<T extends object>( 86 attrs: Attrs<T>, 87): Struct<T> { 88 let entries = Object.entries(attrs) as [ 89 keyof Attrs<T>, 90 Attrs<T>[keyof Attrs<T>], 91 ][]; 92 93 let acc = { 94 layout: [] as Struct<T>["layout"], 95 offset: 0, 96 }; 97 98 let byteAlign = Math.max( 99 ...entries.map(([, typedef]) => typedef.byteAlign), 100 ) as Alignment; 101 102 for (let [name, typedef] of entries) { 103 let padding = pad(acc.offset, typedef.byteAlign); 104 if (padding > 0) { 105 acc.layout.push({ type: "padding", byteLength: padding }); 106 acc.offset += padding; 107 } 108 109 acc.layout.push({ 110 type: "field", 111 name: name as string, 112 offset: acc.offset, 113 typedef, 114 }); 115 acc.offset += typedef.byteLength; 116 } 117 118 let padding = pad(acc.offset, byteAlign); 119 if (padding > 0) { 120 acc.layout.push({ type: "padding", byteLength: padding }); 121 acc.offset += padding; 122 } 123 124 return { 125 type: "struct", 126 layout: acc.layout, 127 byteLength: acc.offset, 128 byteAlign, 129 }; 130} 131 132export function offsets<T extends object>( 133 def: Struct<T>, 134): { [K in keyof T]: number } { 135 let result = {} as { [K in keyof T]: number }; 136 for (let element of def.layout) { 137 if (element.type === "field") { 138 result[element.name as keyof T] = element.offset; 139 } 140 } 141 return result; 142} 143 144export function pad(offset: number, alignment: number): number { 145 if ((offset % alignment) !== 0) { 146 return alignment - (offset % alignment); 147 } else { 148 return 0; 149 } 150}