src/Pure/PIDE/byte_message.ML
author wenzelm
Thu, 06 Jun 2024 11:53:52 +0200
changeset 80266 d52be75ae60b
parent 76183 8089593a364a
child 80565 2acdaa0a7d29
permissions -rw-r--r--
tuned signature;
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
76183
8089593a364a proper file headers;
wenzelm
parents: 75615
diff changeset
     1
(*  Title:      Pure/PIDE/byte_message.ML
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     2
    Author:     Makarius
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     3
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     4
Byte-oriented messages.
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     5
*)
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     6
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     7
signature BYTE_MESSAGE =
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     8
sig
75577
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
     9
  val write: BinIO.outstream -> Bytes.T list -> unit
73558
a5d1d1e2f109 tuned signature;
wenzelm
parents: 70993
diff changeset
    10
  val write_yxml: BinIO.outstream -> XML.tree -> unit
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    11
  val flush: BinIO.outstream -> unit
75577
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    12
  val write_line: BinIO.outstream -> Bytes.T -> unit
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    13
  val read: BinIO.instream -> int -> Bytes.T
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    14
  val read_block: BinIO.instream -> int -> Bytes.T option * int
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    15
  val read_line: BinIO.instream -> Bytes.T option
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    16
  val write_message: BinIO.outstream -> Bytes.T list -> unit
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    17
  val write_message_string: BinIO.outstream -> string list -> unit
73559
22b5ecb53dd9 more uniform use of Byte_Message;
wenzelm
parents: 73558
diff changeset
    18
  val write_message_yxml: BinIO.outstream -> XML.body list -> unit
75577
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    19
  val read_message: BinIO.instream -> Bytes.T list option
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    20
  val read_message_string: BinIO.instream -> string list option
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    21
  val write_line_message: BinIO.outstream -> Bytes.T -> unit
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    22
  val read_line_message: BinIO.instream -> Bytes.T option
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    23
end;
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    24
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    25
structure Byte_Message: BYTE_MESSAGE =
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    26
struct
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    27
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    28
(* output operations *)
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    29
75577
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    30
val write = List.app o Bytes.write_stream;
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    31
75615
4494cd69f97f clarified modules;
wenzelm
parents: 75577
diff changeset
    32
fun write_yxml stream tree =
4494cd69f97f clarified modules;
wenzelm
parents: 75577
diff changeset
    33
  YXML.traverse (fn s => fn () => File_Stream.output stream s) tree ();
73558
a5d1d1e2f109 tuned signature;
wenzelm
parents: 70993
diff changeset
    34
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    35
fun flush stream = ignore (try BinIO.flushOut stream);
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    36
75577
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    37
fun write_line stream bs = (write stream [bs, Bytes.newline]; flush stream);
69467
e8893c893241 tuned signature;
wenzelm
parents: 69454
diff changeset
    38
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    39
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    40
(* input operations *)
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    41
75577
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    42
fun read stream n = Bytes.read_stream n stream;
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    43
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    44
fun read_block stream n =
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    45
  let
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    46
    val msg = read stream n;
75577
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    47
    val len = Bytes.length msg;
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    48
  in (if len = n then SOME msg else NONE, len) end;
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    49
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    50
fun read_line stream =
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    51
  let
75577
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    52
    val result = SOME o Bytes.trim_line;
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    53
    fun read_body bs =
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    54
      (case BinIO.input1 stream of
75577
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    55
        NONE => if Bytes.is_empty bs then NONE else result bs
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    56
      | SOME b =>
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    57
          (case Byte.byteToChar b of
75577
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    58
            #"\n" => result bs
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    59
          | c => read_body (Bytes.add (str c) bs)));
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    60
  in read_body Bytes.empty end;
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    61
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    62
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    63
(* messages with multiple chunks (arbitrary content) *)
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    64
69848
wenzelm
parents: 69467
diff changeset
    65
fun make_header ns =
75577
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    66
  [Bytes.string (space_implode "," (map Value.print_int ns)), Bytes.newline];
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    67
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    68
fun write_message stream chunks =
75577
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    69
  (write stream (make_header (map Bytes.length chunks) @ chunks); flush stream);
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    70
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    71
fun write_message_string stream =
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    72
  write_message stream o map Bytes.string;
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    73
73559
22b5ecb53dd9 more uniform use of Byte_Message;
wenzelm
parents: 73558
diff changeset
    74
fun write_message_yxml stream chunks =
22b5ecb53dd9 more uniform use of Byte_Message;
wenzelm
parents: 73558
diff changeset
    75
  (write stream (make_header (map YXML.body_size chunks));
22b5ecb53dd9 more uniform use of Byte_Message;
wenzelm
parents: 73558
diff changeset
    76
   (List.app o List.app) (write_yxml stream) chunks;
22b5ecb53dd9 more uniform use of Byte_Message;
wenzelm
parents: 73558
diff changeset
    77
   flush stream);
22b5ecb53dd9 more uniform use of Byte_Message;
wenzelm
parents: 73558
diff changeset
    78
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    79
fun parse_header line =
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    80
  map Value.parse_nat (space_explode "," line)
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    81
    handle Fail _ => error ("Malformed message header: " ^ quote line);
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    82
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    83
fun read_chunk stream n =
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    84
  (case read_block stream n of
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    85
    (SOME chunk, _) => chunk
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    86
  | (NONE, len) =>
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    87
      error ("Malformed message chunk: unexpected EOF after " ^
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    88
        string_of_int len ^ " of " ^ string_of_int n ^ " bytes"));
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    89
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    90
fun read_message stream =
75577
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    91
  read_line stream |> Option.map (Bytes.content #> parse_header #> map (read_chunk stream));
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    92
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    93
fun read_message_string stream =
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    94
  read_message stream |> (Option.map o map) Bytes.content;
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    95
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    96
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    97
(* hybrid messages: line or length+block (with content restriction) *)
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    98
75577
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
    99
(* line message format *)
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
   100
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
   101
fun is_length msg =
75577
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
   102
  not (Bytes.is_empty msg) andalso Bytes.forall_string Symbol.is_ascii_digit msg;
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   103
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
   104
fun is_terminated msg =
75577
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
   105
  (case Bytes.last_string msg of
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
   106
    NONE => false
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
   107
  | SOME s => Symbol.is_ascii_line_terminator s);
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   108
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   109
fun write_line_message stream msg =
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
   110
  if is_length msg orelse is_terminated msg then
75577
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
   111
    error ("Bad content for line message:\n" ^ Bytes.beginning 100 msg)
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   112
  else
75577
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
   113
    let val n = Bytes.length msg in
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
   114
      write stream
75577
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
   115
        ((if n > 100 orelse Bytes.exists_string (fn s => s = "\n") msg
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
   116
          then make_header [n + 1] else []) @ [msg, Bytes.newline]);
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   117
      flush stream
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   118
    end;
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   119
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   120
fun read_line_message stream =
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   121
  (case read_line stream of
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
   122
    NONE => NONE
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
   123
  | SOME line =>
75577
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
   124
      (case try (Value.parse_nat o Bytes.content) line of
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   125
        NONE => SOME line
75577
c51e1cef1eae more scalable byte messages, notably for Scala functions in ML;
wenzelm
parents: 75571
diff changeset
   126
      | SOME n => Option.map Bytes.trim_line (#1 (read_block stream n))));
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   127
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   128
end;