src/Pure/PIDE/byte_message.ML
author wenzelm
Wed, 02 Mar 2022 21:14:09 +0100
changeset 75189 f304a2a5080f
parent 73559 22b5ecb53dd9
child 75569 f848f66a8cb7
permissions -rw-r--r--
tuned signature;
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     1
(*  Title:      Pure/General/byte_message.ML
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
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
     9
  val write: BinIO.outstream -> string 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
69467
e8893c893241 tuned signature;
wenzelm
parents: 69454
diff changeset
    12
  val write_line: BinIO.outstream -> string -> unit
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    13
  val read: BinIO.instream -> int -> string
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    14
  val read_block: BinIO.instream -> int -> string option * int
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    15
  val read_line: BinIO.instream -> string option
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    16
  val write_message: BinIO.outstream -> string list -> unit
73559
22b5ecb53dd9 more uniform use of Byte_Message;
wenzelm
parents: 73558
diff changeset
    17
  val write_message_yxml: BinIO.outstream -> XML.body list -> unit
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    18
  val read_message: BinIO.instream -> string list option
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    19
  val write_line_message: BinIO.outstream -> string -> unit
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    20
  val read_line_message: BinIO.instream -> string option
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    21
end;
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    22
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    23
structure Byte_Message: BYTE_MESSAGE =
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    24
struct
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    25
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    26
(* output operations *)
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    27
70993
wenzelm
parents: 69848
diff changeset
    28
fun write stream = List.app (File.output stream);
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    29
73558
a5d1d1e2f109 tuned signature;
wenzelm
parents: 70993
diff changeset
    30
fun write_yxml stream tree = YXML.traverse (fn s => fn () => File.output stream s) tree ();
a5d1d1e2f109 tuned signature;
wenzelm
parents: 70993
diff changeset
    31
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    32
fun flush stream = ignore (try BinIO.flushOut stream);
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    33
69467
e8893c893241 tuned signature;
wenzelm
parents: 69454
diff changeset
    34
fun write_line stream s = (write stream [s, "\n"]; flush stream);
e8893c893241 tuned signature;
wenzelm
parents: 69454
diff changeset
    35
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    36
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    37
(* input operations *)
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    38
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    39
fun read stream n = Byte.bytesToString (BinIO.inputN (stream, n));
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    40
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    41
fun read_block stream n =
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    42
  let
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    43
    val msg = read stream n;
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    44
    val len = size msg;
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    45
  in (if len = n then SOME msg else NONE, len) end;
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    46
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    47
fun read_line stream =
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    48
  let
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    49
    val result = trim_line o String.implode o rev;
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    50
    fun read_body cs =
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    51
      (case BinIO.input1 stream of
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    52
        NONE => if null cs then NONE else SOME (result cs)
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    53
      | SOME b =>
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    54
          (case Byte.byteToChar b of
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    55
            #"\n" => SOME (result cs)
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    56
          | c => read_body (c :: cs)));
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    57
  in read_body [] end;
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    58
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    59
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    60
(* messages with multiple chunks (arbitrary content) *)
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    61
69848
wenzelm
parents: 69467
diff changeset
    62
fun make_header ns =
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    63
  [space_implode "," (map Value.print_int ns), "\n"];
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    64
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    65
fun write_message stream chunks =
69848
wenzelm
parents: 69467
diff changeset
    66
  (write stream (make_header (map size chunks) @ chunks); flush stream);
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    67
73559
22b5ecb53dd9 more uniform use of Byte_Message;
wenzelm
parents: 73558
diff changeset
    68
fun write_message_yxml stream chunks =
22b5ecb53dd9 more uniform use of Byte_Message;
wenzelm
parents: 73558
diff changeset
    69
  (write stream (make_header (map YXML.body_size chunks));
22b5ecb53dd9 more uniform use of Byte_Message;
wenzelm
parents: 73558
diff changeset
    70
   (List.app o List.app) (write_yxml stream) chunks;
22b5ecb53dd9 more uniform use of Byte_Message;
wenzelm
parents: 73558
diff changeset
    71
   flush stream);
22b5ecb53dd9 more uniform use of Byte_Message;
wenzelm
parents: 73558
diff changeset
    72
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    73
fun parse_header line =
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    74
  map Value.parse_nat (space_explode "," line)
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    75
    handle Fail _ => error ("Malformed message header: " ^ quote line);
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    76
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    77
fun read_chunk stream n =
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    78
  (case read_block stream n of
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    79
    (SOME chunk, _) => chunk
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    80
  | (NONE, len) =>
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    81
      error ("Malformed message chunk: unexpected EOF after " ^
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    82
        string_of_int len ^ " of " ^ string_of_int n ^ " bytes"));
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    83
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    84
fun read_message stream =
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    85
  read_line stream |> Option.map (parse_header #> map (read_chunk stream));
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    86
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    87
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    88
(* hybrid messages: line or length+block (with content restriction) *)
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    89
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    90
fun is_length msg =
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    91
  msg <> "" andalso forall_string Symbol.is_ascii_digit msg;
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    92
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    93
fun is_terminated msg =
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    94
  let val len = size msg
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    95
  in len > 0 andalso Symbol.is_ascii_line_terminator (str (String.sub (msg, len - 1))) end;
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    96
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    97
fun write_line_message stream msg =
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    98
  if is_length msg orelse is_terminated msg then
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    99
    error ("Bad content for line message:\n" ^ implode (take 100 (Symbol.explode msg)))
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   100
  else
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   101
    let val n = size msg in
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
   102
      write stream
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
   103
        ((if n > 100 orelse exists_string (fn s => s = "\n") msg
69848
wenzelm
parents: 69467
diff changeset
   104
          then make_header [n + 1] else []) @ [msg, "\n"]);
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   105
      flush stream
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   106
    end;
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   107
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   108
fun read_line_message stream =
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   109
  (case read_line stream of
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
   110
    NONE => NONE
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
   111
  | SOME line =>
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   112
      (case try Value.parse_nat line of
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   113
        NONE => SOME line
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
   114
      | SOME n => Option.map trim_line (#1 (read_block stream n))));
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   115
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   116
end;