package ocaml-protoc-plugin

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file reader.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
(** Some buffer to hold data, and to read and write data *)

open StdLabels
open Field
open Result

type t = {
  mutable offset : int;
  end_offset : int;
  data : String.t;
}

let create ?(offset = 0) ?length data =
  let end_offset =
    match length with
    | None -> String.length data
    | Some l -> l + offset
  in
  assert (String.length data >= end_offset);
  {offset; end_offset; data}

(** Return an error if there is not enough data in input *)
let validate_capacity t count =
  match t.offset + count <= t.end_offset with
  | true -> return ()
  | false ->
    Result.fail `Premature_end_of_input

(** Test if there is more data in the buffer to be read *)
let has_more t = t.offset < t.end_offset

let read_byte t =
  validate_capacity t 1 >>| fun () ->
    let v = t.data.[t.offset] in
    t.offset <- t.offset + 1;
    (Char.code v)

let read_raw_varint t =
  let open Infix.Int64 in
  let rec inner acc =
    read_byte t >>= fun v ->
      let v = Int64.of_int v in
      let acc = (v land 0x7FL) :: acc in
      match v > 127L with
      | true ->
        (* Still More data *)
        inner acc
      | false -> Result.return acc
  in
  inner [] >>|
  List.fold_left ~init:0L ~f:(fun acc c -> (acc lsl 7) + c)

let read_varint t = read_raw_varint t >>| fun v -> Varint v

let read_field_header : t -> (int * int) Result.t =
  fun t ->
  let open Infix.Int64 in
  read_raw_varint t >>| fun v ->
    let tpe = v land 0x7L |> Int64.to_int in
    let field_number = v / 8L |> Int64.to_int in
    (tpe, field_number)


let read_length_delimited t =
  read_raw_varint t >>= fun length ->
    let length = Int64.to_int length in
    validate_capacity t length >>| fun () ->
      let v = Length_delimited {offset = t.offset; length; data = t.data} in
      t.offset <- t.offset + length;
      v

(* Implement little endian ourselves *)
let read_fixed32 t =
  let size = 4 in
  validate_capacity t size >>| fun () ->
  let v = LittleEndian.get_int32 t.data t.offset in
  t.offset <- t.offset + size;
  (Fixed_32_bit v)

let read_fixed64 t =
  let size = 8 in
  validate_capacity t size >>| fun () ->
  let v = LittleEndian.get_int64 t.data t.offset in
  t.offset <- t.offset + size;
  (Fixed_64_bit v)

let read_field : t -> (int * Field.t) Result.t =
 fun t ->
  read_field_header t >>= (fun (field_type, field_number) ->
    (match field_type with
    | 0 -> read_varint t
    | 1 -> read_fixed64 t
    | 2 -> read_length_delimited t
    | 5 -> read_fixed32 t
    | n -> Result.fail (`Unknown_field_type n))
    >>| fun field -> (field_number, field)
  )
OCaml

Innovation. Community. Security.