Library Prelude.Data.Bytes


From Coq Require Import RelationClasses Int63.
From Prelude Require Import Init Byte Equality Control Option.

Inductive bytes := wrap_bytes { unwrap_bytes : list byte }.

Register bytes as prelude.data.bytes.type.
Register wrap_bytes as prelude.data.bytes.wrap_bytes.

Declare Scope bytes_scope.
Delimit Scope bytes_scope with bytes.
Bind Scope bytes_scope with bytes.

Definition append (x y : bytes) :=
  wrap_bytes (unwrap_bytes x ++ unwrap_bytes y).

Infix "++" := append : bytes_scope.

Definition length_nat (x : bytes) : nat :=
  List.length (unwrap_bytes x).

Definition length (x : bytes) : int :=
  let fix list_length (x : list byte) (acc : int) : int :=
      match x with
      | _ :: rst => list_length rst (acc + 1)%int63
      | [] => acc
      end
  in list_length (unwrap_bytes x) 0%int63.

Definition bytes_equal (x y : bytes) : Prop :=
  unwrap_bytes x == unwrap_bytes y.

#[program]
Instance bytes_equal_Equivalence : Equivalence bytes_equal.

Next Obligation.
  intros [x].
  cbn.
  induction x.
  + constructor.
  + now constructor.
Qed.

Next Obligation.
  intros [x] [y] equ.
  cbn in *.
  induction equ.
  + constructor.
    ++ now symmetry.
    ++ apply IHequ.
  + constructor.
Qed.

Next Obligation.
  intros [x] [y] [z] equ equ'.
  cbn in *.
  revert y z equ equ'.
  induction x; intros y z equ equ';
    inversion equ; subst; inversion equ'; subst; auto.
  constructor.
  + transitivity y0; auto.
  + eapply IHx; eauto.
Qed.

#[program]
Instance bytes_Equality : Equality bytes :=
  { equal := bytes_equal
  }.

#[program]
Instance bytes_EquDec : EquDec bytes :=
  { equalb := fun (x y : bytes) => unwrap_bytes x ?= unwrap_bytes y
  }.

Next Obligation.
  destruct x as [x]; destruct y as [y].
  cbn.
  split.
  + intros equ.
    assert (equ' : x == y) by apply equ.
    now rewrite equalb_equ_true in equ'.
  + intros equ.
    assert (equ' : x ?= y = true) by apply equ.
    now rewrite <- equalb_equ_true in equ'.
Qed.

#[local]
Fixpoint list_byte_of_list_byte_fmt (i : list byte) : option (list byte) :=
  match i with
  | c#"\" :: c#"0" :: rst => cons c#"\0" <$> list_byte_of_list_byte_fmt rst
  | c#"\" :: c#"n" :: rst => cons c#"\n" <$> list_byte_of_list_byte_fmt rst
  | c#"\" :: c#"r" :: rst => cons c#"\r" <$> list_byte_of_list_byte_fmt rst
  | c#"\" :: c#"t" :: rst => cons c#"\t" <$> list_byte_of_list_byte_fmt rst
  | c#"\" :: c#"\" :: rst => cons c#"\" <$> list_byte_of_list_byte_fmt rst
  | c#"\" :: _ :: rst => None
  | x :: rst => cons x <$> list_byte_of_list_byte_fmt rst
  | [] => Some []
  end.

#[local]
Fixpoint bytes_of_list_byte_fmt (i : list byte) : option bytes :=
  wrap_bytes <$> list_byte_of_list_byte_fmt i.

String Notation bytes bytes_of_list_byte_fmt unwrap_bytes : bytes_scope.
Notation "'b#' c" := (c%bytes) (at level 0, c constr, no associativity, only parsing) : prelude_scope.