STUDIO HAZE · image
Topaz source
Open by house policy. Topaz is our own language.
Topaz 5.9 · 42 files
topaz/src/wire.tpz
Topaz · 15666 B · Original file
1
// Canonical structure wire encoding and decoding.3
import std.bytes { Bytes }4
import std.json5
import util { 바이트로, 바이트배열로, 바이트추가, 부분배열 }7
export record 정수읽기 { 값: int, 다음: int }8
export record 문자열읽기 { 값: string, 다음: int }9
export record 사전읽기 { 값들: Array<string>, 다음: int }10
export record 코드단위문자열 {11
키: string,12
안전값: string,13
안전: bool14
}15
export record 코드단위문자열읽기 { 값: 코드단위문자열, 다음: int }16
export record 코드단위사전읽기 { 값들: Array<코드단위문자열>, 다음: int }17
export record 갈루아표 { 지수: Array<int>, 로그: Array<int> }19
// 구조 와이어의 낱말들. 십육진 표기와 가변 정수와 정렬 사전이20
// 위의 모든 계층이 함께 쓰는 어휘다.21
function 소문자십육진글자(값: int) -> string {22
["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"][값]23
}25
function 대문자십육진글자(값: int) -> string {26
["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"][값]27
}29
function 소문자십육진네자리(값: int) -> string {30
소문자십육진글자((값 / 4096) % 16) + 소문자십육진글자((값 / 256) % 16) +31
소문자십육진글자((값 / 16) % 16) + 소문자십육진글자(값 % 16)32
}34
export function 대문자십육진네자리(값: int) -> string {35
대문자십육진글자((값 / 4096) % 16) + 대문자십육진글자((값 / 256) % 16) +36
대문자십육진글자((값 / 16) % 16) + 대문자십육진글자(값 % 16)37
}39
export function 대문자십육진두자리(값: int) -> string {40
대문자십육진글자((값 / 16) % 16) + 대문자십육진글자(값 % 16)41
}43
function 십육진글자인가(글자: string) -> bool {44
(글자 >= "0" && 글자 <= "9") || (글자 >= "a" && 글자 <= "f") ||45
(글자 >= "A" && 글자 <= "F")46
}48
function 소문자십육진글자인가(글자: string) -> bool {49
(글자 >= "0" && 글자 <= "9") || (글자 >= "a" && 글자 <= "f")50
}52
function 제이슨십육진숫자(글자: string) -> int {53
if 글자 >= "0" && 글자 <= "9" { return (글자.codePointAt(0) ?? 48) - 48 }54
if 글자 >= "a" && 글자 <= "f" { return (글자.codePointAt(0) ?? 97) - 97 + 10 }55
(글자.codePointAt(0) ?? 65) - 65 + 1056
}58
function 높은대리자인가(단위: int) -> bool { 단위 >= 55296 && 단위 <= 56319 }59
function 낮은대리자인가(단위: int) -> bool { 단위 >= 56320 && 단위 <= 57343 }61
export function 널문자있음(값: string) -> bool {62
for 글자 in 값.scalars() {63
if (글자.codePointAt(0) ?? -1) == 0 { return true }64
}65
false66
}68
function 코드단위키만들기(단위들: Array<int>) -> string {69
let mut 조각들: Array<string> = []70
for 단위 in 단위들 { 조각들.push(소문자십육진네자리(단위)) }71
조각들.join("")72
}74
export function 안전문자열코드단위키(값: string) -> string {75
let mut 조각들: Array<string> = []76
for 글자 in 값.scalars() {77
let 코드 = 글자.codePointAt(0) ?? 078
if 코드 <= 65535 { 조각들.push(소문자십육진네자리(코드)) }79
else {80
let 나머지 = 코드 - 6553681
조각들.push(소문자십육진네자리(55296 + 나머지 / 1024))82
조각들.push(소문자십육진네자리(56320 + 나머지 % 1024))83
}84
}85
조각들.join("")86
}88
export function 코드단위키읽기(키: string, 빈값허용: bool) -> Result<Array<int>, string> {89
let 글자들 = 키.scalars()90
if (!빈값허용 && 글자들.length == 0) || 글자들.length % 4 != 0 {91
return Err("UTF-16 코드 단위 키 길이가 틀립니다")92
}93
let mut 단위들: Array<int> = []94
let mut 색인 = 095
while 색인 < 글자들.length {96
let mut 자리 = 097
let mut 값 = 098
while 자리 < 4 {99
let 글자 = 글자들[색인 + 자리]100
if !소문자십육진글자인가(글자) { return Err("UTF-16 코드 단위 키가 소문자 십육진수가 아닙니다") }101
값 = 값 * 16 + 제이슨십육진숫자(글자)102
자리 = 자리 + 1103
}104
단위들.push(값)105
색인 = 색인 + 4106
}107
Ok(단위들)108
}110
export function 짝없는대리자있음(단위들: Array<int>) -> bool {111
let mut 색인 = 0112
while 색인 < 단위들.length {113
let 단위 = 단위들[색인]114
if 높은대리자인가(단위) {115
if 색인 + 1 < 단위들.length && 낮은대리자인가(단위들[색인 + 1]) { 색인 = 색인 + 2 }116
else { return true }117
} else if 낮은대리자인가(단위) { return true }118
else { 색인 = 색인 + 1 }119
}120
false121
}123
function 안전코드단위값(단위들: Array<int>) -> Result<string, string> {124
if 짝없는대리자있음(단위들) { return Err("짝없는 UTF-16 대리자는 Topaz 문자열이 될 수 없습니다") }125
let mut 조각들: Array<string> = []126
let mut 색인 = 0127
while 색인 < 단위들.length {128
let 단위 = 단위들[색인]129
let 코드 = if 높은대리자인가(단위) {130
let 낮음 = 단위들[색인 + 1]131
색인 = 색인 + 2132
65536 + (단위 - 55296) * 1024 + (낮음 - 56320)133
} else {134
색인 = 색인 + 1135
단위136
}137
match fromCodePoint(코드) {138
case Some(글자) => { 조각들.push(글자) }139
case None => return Err("UTF-16 코드 단위가 유니코드 스칼라가 아닙니다")140
}141
}142
Ok(조각들.join(""))143
}145
function 와이어제이슨문자열(키: string) -> Result<string, string> {146
let 단위들 = 코드단위키읽기(키, true)?147
let mut 조각들: Array<string> = ["\""]148
let mut 색인 = 0149
while 색인 < 단위들.length {150
let 단위 = 단위들[색인]151
if 단위 == 34 { 조각들.push("\\\"") }152
else if 단위 == 92 { 조각들.push("\\\\") }153
else if 단위 == 8 { 조각들.push("\\b") }154
else if 단위 == 12 { 조각들.push("\\f") }155
else if 단위 == 10 { 조각들.push("\\n") }156
else if 단위 == 13 { 조각들.push("\\r") }157
else if 단위 == 9 { 조각들.push("\\t") }158
else if 높은대리자인가(단위) && 색인 + 1 < 단위들.length && 낮은대리자인가(단위들[색인 + 1]) {159
let 코드 = 65536 + (단위 - 55296) * 1024 + (단위들[색인 + 1] - 56320)160
match fromCodePoint(코드) {161
case Some(문자) => { 조각들.push(문자) }162
case None => return Err("UTF-16 대리자 쌍이 유니코드 스칼라가 아닙니다")163
}164
색인 = 색인 + 1165
} else if 높은대리자인가(단위) || 낮은대리자인가(단위) || 단위 < 32 {166
조각들.push("\\u")167
조각들.push(소문자십육진네자리(단위))168
} else {169
match fromCodePoint(단위) {170
case Some(문자) => { 조각들.push(문자) }171
case None => return Err("UTF-16 코드 단위가 유니코드 스칼라가 아닙니다")172
}173
}174
색인 = 색인 + 1175
}176
조각들.push("\"")177
Ok(조각들.join(""))178
}180
export function 코드단위문자열만들기(키: string) -> Result<코드단위문자열, string> {181
let 단위들 = 코드단위키읽기(키, true)?182
if 짝없는대리자있음(단위들) {183
return Ok(코드단위문자열 { 키: 키, 안전값: "", 안전: false })184
}185
Ok(코드단위문자열 { 키: 키, 안전값: 안전코드단위값(단위들)?, 안전: true })186
}188
function 제이슨문자열코드단위로(직렬: string) -> Result<코드단위문자열, string> {189
let 글자들 = 직렬.scalars()190
if 글자들.length < 2 || 글자들[0] != "\"" || 글자들[글자들.length - 1] != "\"" {191
return Err("스칼라 문자열 사전 값이 JSON 문자열이 아닙니다")192
}193
let mut 단위들: Array<int> = []194
let mut 색인 = 1195
while 색인 < 글자들.length - 1 {196
let 글자 = 글자들[색인]197
if 글자 == "\"" { return Err("스칼라 문자열 사전에 닫는 따옴표 뒤 글자가 있습니다") }198
if 글자 == "\\" {199
if 색인 + 1 >= 글자들.length - 1 { return Err("스칼라 문자열 사전의 탈출 문자가 잘렸습니다") }200
let 탈출 = 글자들[색인 + 1]201
if 탈출 == "u" {202
if 색인 + 5 >= 글자들.length - 1 { return Err("스칼라 문자열 사전의 유니코드 탈출이 잘렸습니다") }203
let mut 자리 = 0204
let mut 단위 = 0205
while 자리 < 4 {206
let 숫자글자 = 글자들[색인 + 2 + 자리]207
if !십육진글자인가(숫자글자) { return Err("스칼라 문자열 사전의 유니코드 탈출이 틀립니다") }208
단위 = 단위 * 16 + 제이슨십육진숫자(숫자글자)209
자리 = 자리 + 1210
}211
단위들.push(단위)212
색인 = 색인 + 6213
} else {214
if 탈출 == "\"" { 단위들.push(34) }215
else if 탈출 == "\\" { 단위들.push(92) }216
else if 탈출 == "/" { 단위들.push(47) }217
else if 탈출 == "b" { 단위들.push(8) }218
else if 탈출 == "f" { 단위들.push(12) }219
else if 탈출 == "n" { 단위들.push(10) }220
else if 탈출 == "r" { 단위들.push(13) }221
else if 탈출 == "t" { 단위들.push(9) }222
else { return Err("스칼라 문자열 사전의 탈출 문자가 틀립니다") }223
색인 = 색인 + 2224
}225
} else {226
let 코드 = 글자.codePointAt(0) ?? -1227
if 코드 < 32 { return Err("스칼라 문자열 사전에 탈출하지 않은 제어 문자가 있습니다") }228
if 코드 <= 65535 { 단위들.push(코드) }229
else {230
let 나머지 = 코드 - 65536231
단위들.push(55296 + 나머지 / 1024)232
단위들.push(56320 + 나머지 % 1024)233
}234
색인 = 색인 + 1235
}236
}237
if 색인 != 글자들.length - 1 { return Err("스칼라 문자열 사전 값 길이가 틀립니다") }238
let 키 = 코드단위키만들기(단위들)239
if 와이어제이슨문자열(키)? != 직렬 { return Err("스칼라 문자열 사전 값이 정규 JSON이 아닙니다") }240
if 짝없는대리자있음(단위들) {241
Ok(코드단위문자열 { 키: 키, 안전값: "", 안전: false })242
} else {243
Ok(코드단위문자열 { 키: 키, 안전값: JSON.parseAs<string>(직렬)?, 안전: true })244
}245
}247
export function 사전색인(값들: Array<string>, 찾기: string) -> int {248
let mut 색인 = 0249
while 색인 < 값들.length {250
if 값들[색인] == 찾기 { return 색인 }251
색인 = 색인 + 1252
}253
-1254
}256
export function 정렬고유(값들: Array<string>) -> Array<string> {257
let 정렬 = 값들.sorted()258
let mut 결과: Array<string> = []259
for 값 in 정렬 {260
if 결과.length == 0 || 결과[결과.length - 1] != 값 { 결과.push(값) }261
}262
결과263
}265
export function 가변정수쓰기(출력: Array<int>, 원본: int) -> Array<int> {266
let mut 결과 = 출력267
let mut 남음 = 원본268
while 남음 >= 128 {269
결과.push((남음 % 128) + 128)270
남음 = 남음 / 128271
}272
결과.push(남음)273
결과274
}276
export function 삼십이쓰기(출력: Array<int>, 값: int) -> Array<int> {277
let mut 결과 = 출력278
결과.push((값 / 16777216) % 256)279
결과.push((값 / 65536) % 256)280
결과.push((값 / 256) % 256)281
결과.push(값 % 256)282
결과283
}285
export function 삼십이읽기(입력: Array<int>, 위치: int) -> int {286
입력[위치] * 16777216 + 입력[위치 + 1] * 65536 + 입력[위치 + 2] * 256 + 입력[위치 + 3]287
}289
function 정규문자열쓰기(출력: Array<int>, 값: string) -> Result<Array<int>, string> {290
let 직렬 = JSON.stringify(값)?291
let 바이트들 = 바이트배열로(Bytes.encodeUtf8(직렬))292
let 길이쓴 = 가변정수쓰기(출력, 바이트들.length)293
Ok(바이트추가(길이쓴, 바이트들))294
}296
function 코드단위문자열쓰기(출력: Array<int>, 키: string) -> Result<Array<int>, string> {297
let 직렬 = 와이어제이슨문자열(키)?298
let 바이트들 = 바이트배열로(Bytes.encodeUtf8(직렬))299
let 길이쓴 = 가변정수쓰기(출력, 바이트들.length)300
Ok(바이트추가(길이쓴, 바이트들))301
}303
export function 사전쓰기(출력: Array<int>, 값들: Array<string>) -> Result<Array<int>, string> {304
let mut 결과 = 가변정수쓰기(출력, 값들.length)305
for 값 in 값들 { 결과 = 정규문자열쓰기(결과, 값)? }306
Ok(결과)307
}309
export function 코드단위사전쓰기(출력: Array<int>, 키들: Array<string>) -> Result<Array<int>, string> {310
let mut 결과 = 가변정수쓰기(출력, 키들.length)311
for 키 in 키들 { 결과 = 코드단위문자열쓰기(결과, 키)? }312
Ok(결과)313
}315
export function 가변정수읽기(입력: Array<int>, 시작: int) -> Result<정수읽기, string> {316
let mut 값 = 0317
let mut 배수 = 1318
let mut 위치 = 시작319
let mut 색인 = 0320
while 색인 < 8 {321
if 위치 >= 입력.length { return Err("가변 정수가 잘렸습니다") }322
let 바이트 = 입력[위치]323
위치 = 위치 + 1324
let 숫자 = 바이트 % 128325
if 숫자 > (9007199254740991 - 값) / 배수 { return Err("가변 정수가 안전 범위를 넘습니다") }326
값 = 값 + 숫자 * 배수327
if 바이트 < 128 { return Ok(정수읽기 { 값: 값, 다음: 위치 }) }328
배수 = 배수 * 128329
색인 = 색인 + 1330
}331
Err("가변 정수가 너무 깁니다")332
}334
function 정규문자열읽기(입력: Array<int>, 시작: int) -> Result<문자열읽기, string> {335
let 길이읽기 = 가변정수읽기(입력, 시작)?336
let 끝 = 길이읽기.다음 + 길이읽기.값337
if 끝 > 입력.length { return Err("문자열이 잘렸습니다") }338
let 조각 = 바이트로(부분배열(입력, 길이읽기.다음, 끝))?339
let 직렬 = 조각.decodeUtf8()?340
let 값 = JSON.parseAs<string>(직렬)?341
if JSON.stringify(값)? != 직렬 { return Err("문자열이 정규 JSON이 아닙니다") }342
Ok(문자열읽기 { 값: 값, 다음: 끝 })343
}345
function 코드단위문자열해석(입력: Array<int>, 시작: int) -> Result<코드단위문자열읽기, string> {346
let 길이읽기 = 가변정수읽기(입력, 시작)?347
let 끝 = 길이읽기.다음 + 길이읽기.값348
if 끝 > 입력.length { return Err("스칼라 문자열이 잘렸습니다") }349
let 조각 = 바이트로(부분배열(입력, 길이읽기.다음, 끝))?350
let 직렬 = 조각.decodeUtf8()?351
Ok(코드단위문자열읽기 { 값: 제이슨문자열코드단위로(직렬)?, 다음: 끝 })352
}354
export function 사전해석(입력: Array<int>, 시작: int) -> Result<사전읽기, string> {355
let 수읽기 = 가변정수읽기(입력, 시작)?356
let mut 위치 = 수읽기.다음357
let mut 값들: Array<string> = []358
let mut 색인 = 0359
while 색인 < 수읽기.값 {360
let 읽기 = 정규문자열읽기(입력, 위치)?361
if 색인 > 0 && 값들[색인 - 1] >= 읽기.값 { return Err("사전이 엄격히 정렬되지 않았습니다") }362
값들.push(읽기.값)363
위치 = 읽기.다음364
색인 = 색인 + 1365
}366
Ok(사전읽기 { 값들: 값들, 다음: 위치 })367
}369
export function 코드단위사전해석(입력: Array<int>, 시작: int) -> Result<코드단위사전읽기, string> {370
let 수읽기 = 가변정수읽기(입력, 시작)?371
let mut 위치 = 수읽기.다음372
let mut 값들: Array<코드단위문자열> = []373
let mut 색인 = 0374
while 색인 < 수읽기.값 {375
let 읽기 = 코드단위문자열해석(입력, 위치)?376
if 색인 > 0 && 값들[색인 - 1].키 >= 읽기.값.키 {377
return Err("스칼라 문자열 사전이 UTF-16 코드 단위 순서로 정렬되지 않았습니다")378
}379
값들.push(읽기.값)380
위치 = 읽기.다음381
색인 = 색인 + 1382
}383
Ok(코드단위사전읽기 { 값들: 값들, 다음: 위치 })384
}SHA256 20a34b118b86712c60ba6fbe6a5f91b532bbc01d63fa1e0c421db2d77cca8e44