Appearance
| 1 | namespace Analysis.Protocol is | |
| 2 | use System.Text.Json.JsonSerializer; | |
| 3 | use System.Text.Json.JsonSerializerOptions; | |
| 4 | ||
| 5 | // Wire helper for the JSON analysis protocol. One JSON object per line, | |
| 6 | // newline-terminated; a message never contains a raw newline (JSON escapes | |
| 7 | // them inside strings), so `read_line` is a complete framing primitive. | |
| 8 | // | |
| 9 | // Requests deserialize into the REQUEST discriminated union (by the | |
| 10 | // `command` field); responses serialize from the RESPONSE union (tagged | |
| 11 | // with `kind`). Wire field names are the ghūl property names verbatim | |
| 12 | // (snake_case); no `JsonNamingPolicy` is applied. | |
| 13 | class JSON_PROTOCOL is | |
| 14 | _options: JsonSerializerOptions? static; | |
| 15 | ||
| 16 | options: JsonSerializerOptions static is | |
| 17 | let options mut = _options; | |
| 18 | ||
| 19 | if !options? then | |
| 20 | options = JsonSerializerOptions(); | |
| 21 | ||
| 22 | // Variant constructor args emit as public CLR fields, not | |
| 23 | // properties — System.Text.Json's default is to skip | |
| 24 | // fields. Required for both the Request union (variants | |
| 25 | // carry path/line/column etc. via fields) and the Response | |
| 26 | // union (every variant body is a constructor field). | |
| 27 | options.include_fields = true; | |
| 28 | ||
| 29 | _options = options; | |
| 30 | fi | |
| 31 | ||
| 32 | return options; | |
| 33 | si | |
| 34 | ||
| 35 | // Read one request line, skipping blank lines. Returns null at | |
| 36 | // end-of-input. A malformed line throws out of JsonSerializer; the | |
| 37 | // despatcher catches and requests a restart. | |
| 38 | read_request(reader: IO.TextReader) -> Request? static is | |
| 39 | do | |
| 40 | let line = reader.read_line(); | |
| 41 | ||
| 42 | if !line? then | |
| 43 | return null; | |
| 44 | fi | |
| 45 | ||
| 46 | if string.is_null_or_white_space(line) then | |
| 47 | continue; | |
| 48 | fi | |
| 49 | ||
| 50 | return JsonSerializer.deserialize[Request](line, options); | |
| 51 | od | |
| 52 | si | |
| 53 | ||
| 54 | // Serialize a response onto a single line and flush. Every response | |
| 55 | // frame is one line; the client splits stdout on '\n'. | |
| 56 | write_response(writer: IO.TextWriter, response: Response) static is | |
| 57 | writer.write(JsonSerializer.serialize[Response](response, options)); | |
| 58 | writer.write("\n"); | |
| 59 | writer.flush(); | |
| 60 | si | |
| 61 | si | |
| 62 | si |