src/Pure/PIDE/byte_message.scala
author paulson <lp15@cam.ac.uk>
Fri, 08 Aug 2025 16:46:03 +0100
changeset 82969 dedd9d13c79c
parent 80549 769a52499f12
permissions -rw-r--r--
Generalised a theorem about Lebesgue integration
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
77570
98b4a9902582 tuned headers;
wenzelm
parents: 75393
diff changeset
     1
/*  Title:      Pure/PIDE/byte_message.scala
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
package isabelle
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
     8
80392
c22a56495b4c tuned: prefer Bytes operations;
wenzelm
parents: 80390
diff changeset
     9
import java.io.{OutputStream, InputStream, IOException}
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    10
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    11
75393
87ebf5a50283 clarified formatting, for the sake of scala3;
wenzelm
parents: 73340
diff changeset
    12
object Byte_Message {
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    13
  /* output operations */
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    14
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    15
  def write(stream: OutputStream, bytes: List[Bytes]): Unit =
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    16
    bytes.foreach(_.write_stream(stream))
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    17
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    18
  def flush(stream: OutputStream): Unit =
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    19
    try { stream.flush() }
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    20
    catch { case _: IOException => }
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    21
75393
87ebf5a50283 clarified formatting, for the sake of scala3;
wenzelm
parents: 73340
diff changeset
    22
  def write_line(stream: OutputStream, bytes: Bytes): Unit = {
69467
e8893c893241 tuned signature;
wenzelm
parents: 69454
diff changeset
    23
    write(stream, List(bytes, Bytes.newline))
e8893c893241 tuned signature;
wenzelm
parents: 69454
diff changeset
    24
    flush(stream)
e8893c893241 tuned signature;
wenzelm
parents: 69454
diff changeset
    25
  }
e8893c893241 tuned signature;
wenzelm
parents: 69454
diff changeset
    26
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    27
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    28
  /* input operations */
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    29
80390
6f48f96f7997 proper treatment of long message blocks;
wenzelm
parents: 80386
diff changeset
    30
  def read(stream: InputStream, n: Long): Bytes =
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    31
    Bytes.read_stream(stream, limit = n)
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    32
80390
6f48f96f7997 proper treatment of long message blocks;
wenzelm
parents: 80386
diff changeset
    33
  def read_block(stream: InputStream, n: Long): (Option[Bytes], Long) = {
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    34
    val msg = read(stream, n)
80357
fe123d033e76 clarified signature: pro-forma support for Bytes with size: Long;
wenzelm
parents: 80353
diff changeset
    35
    val len = msg.size
80390
6f48f96f7997 proper treatment of long message blocks;
wenzelm
parents: 80386
diff changeset
    36
    (if (len == n) Some(msg) else None, len)
69449
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    37
  }
b516fdf8005c more uniform multi-language operations;
wenzelm
parents: 69448
diff changeset
    38
75393
87ebf5a50283 clarified formatting, for the sake of scala3;
wenzelm
parents: 73340
diff changeset
    39
  def read_line(stream: InputStream): Option[Bytes] = {
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    40
    var c = 0
80392
c22a56495b4c tuned: prefer Bytes operations;
wenzelm
parents: 80390
diff changeset
    41
    val line =
c22a56495b4c tuned: prefer Bytes operations;
wenzelm
parents: 80390
diff changeset
    42
      Bytes.Builder.use(hint = 100) { builder =>
c22a56495b4c tuned: prefer Bytes operations;
wenzelm
parents: 80390
diff changeset
    43
        while ({ c = stream.read; c != -1 && c != 10 }) {
c22a56495b4c tuned: prefer Bytes operations;
wenzelm
parents: 80390
diff changeset
    44
          builder += c.toByte
c22a56495b4c tuned: prefer Bytes operations;
wenzelm
parents: 80390
diff changeset
    45
        }
c22a56495b4c tuned: prefer Bytes operations;
wenzelm
parents: 80390
diff changeset
    46
      }
80549
wenzelm
parents: 80548
diff changeset
    47
    if (c == -1 && line.is_empty) None else Some(line.trim_line)
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    48
  }
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    49
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    50
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    51
  /* messages with multiple chunks (arbitrary content) */
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    52
80357
fe123d033e76 clarified signature: pro-forma support for Bytes with size: Long;
wenzelm
parents: 80353
diff changeset
    53
  private def make_header(ns: List[Long]): List[Bytes] =
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    54
    List(Bytes(ns.mkString(",")), Bytes.newline)
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    55
75393
87ebf5a50283 clarified formatting, for the sake of scala3;
wenzelm
parents: 73340
diff changeset
    56
  def write_message(stream: OutputStream, chunks: List[Bytes]): Unit = {
80357
fe123d033e76 clarified signature: pro-forma support for Bytes with size: Long;
wenzelm
parents: 80353
diff changeset
    57
    write(stream, make_header(chunks.map(_.size)) ::: chunks)
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    58
    flush(stream)
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    59
  }
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    60
80390
6f48f96f7997 proper treatment of long message blocks;
wenzelm
parents: 80386
diff changeset
    61
  private def parse_header(line: String): List[Long] = {
6f48f96f7997 proper treatment of long message blocks;
wenzelm
parents: 80386
diff changeset
    62
    val args = space_explode(',', line)
6f48f96f7997 proper treatment of long message blocks;
wenzelm
parents: 80386
diff changeset
    63
    if (args.forall(is_length)) args.map(Value.Long.parse)
6f48f96f7997 proper treatment of long message blocks;
wenzelm
parents: 80386
diff changeset
    64
    else error("Malformed message header: " + quote(line))
6f48f96f7997 proper treatment of long message blocks;
wenzelm
parents: 80386
diff changeset
    65
  }
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    66
80390
6f48f96f7997 proper treatment of long message blocks;
wenzelm
parents: 80386
diff changeset
    67
  private def read_chunk(stream: InputStream, n: Long): Bytes =
69452
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    68
    read_block(stream, n) match {
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    69
      case (Some(chunk), _) => chunk
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    70
      case (None, len) =>
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    71
        error("Malformed message chunk: unexpected EOF after " + len + " of " + n + " bytes")
704915cf59fa more uniform multi-language operations;
wenzelm
parents: 69451
diff changeset
    72
    }
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    73
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    74
  def read_message(stream: InputStream): Option[List[Bytes]] =
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    75
    read_line(stream).map(line => parse_header(line.text).map(read_chunk(stream, _)))
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    76
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    77
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    78
  /* hybrid messages: line or length+block (restricted content) */
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    79
80390
6f48f96f7997 proper treatment of long message blocks;
wenzelm
parents: 80386
diff changeset
    80
  private def is_length(str: String): Boolean =
6f48f96f7997 proper treatment of long message blocks;
wenzelm
parents: 80386
diff changeset
    81
    !str.isEmpty && str.iterator.forall(Symbol.is_ascii_digit) &&
6f48f96f7997 proper treatment of long message blocks;
wenzelm
parents: 80386
diff changeset
    82
      Value.Long.unapply(str).isDefined
6f48f96f7997 proper treatment of long message blocks;
wenzelm
parents: 80386
diff changeset
    83
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    84
  private def is_length(msg: Bytes): Boolean =
80548
d1662f1296db tuned signature;
wenzelm
parents: 80493
diff changeset
    85
    !msg.is_empty && msg.byte_iterator.forall(Symbol.is_ascii_digit) &&
80390
6f48f96f7997 proper treatment of long message blocks;
wenzelm
parents: 80386
diff changeset
    86
      Value.Long.unapply(msg.text).isDefined
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    87
75393
87ebf5a50283 clarified formatting, for the sake of scala3;
wenzelm
parents: 73340
diff changeset
    88
  def write_line_message(stream: OutputStream, msg: Bytes): Unit = {
80493
d334f158442b clarified signature: more direct operation;
wenzelm
parents: 80392
diff changeset
    89
    if (is_length(msg) || msg.terminated_line) {
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    90
      error ("Bad content for line message:\n" ++ msg.text.take(100))
80386
wenzelm
parents: 80362
diff changeset
    91
    }
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    92
80357
fe123d033e76 clarified signature: pro-forma support for Bytes with size: Long;
wenzelm
parents: 80353
diff changeset
    93
    val n = msg.size
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    94
    write(stream,
80362
d395b7e14102 clarified signature;
wenzelm
parents: 80357
diff changeset
    95
      (if (n > 100 || msg.byte_iterator.contains(10)) make_header(List(n + 1)) else Nil) :::
69454
ef051edd4d10 more uniform multi-language operations;
wenzelm
parents: 69452
diff changeset
    96
        List(msg, Bytes.newline))
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
    97
    flush(stream)
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    98
  }
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
    99
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   100
  def read_line_message(stream: InputStream): Option[Bytes] =
69451
387894c2fb2c more uniform multi-language operations;
wenzelm
parents: 69449
diff changeset
   101
    read_line(stream) match {
80390
6f48f96f7997 proper treatment of long message blocks;
wenzelm
parents: 80386
diff changeset
   102
      case Some(line) if is_length(line) =>
6f48f96f7997 proper treatment of long message blocks;
wenzelm
parents: 80386
diff changeset
   103
        val n = Value.Long.parse(line.text)
6f48f96f7997 proper treatment of long message blocks;
wenzelm
parents: 80386
diff changeset
   104
        read_block(stream, n)._1.map(_.trim_line)
6f48f96f7997 proper treatment of long message blocks;
wenzelm
parents: 80386
diff changeset
   105
      case res => res
69448
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   106
    }
51e696887b81 more uniform multi-language operations;
wenzelm
parents:
diff changeset
   107
}