Fixpoint inj_value_rec (n: nat) (v: val) (q: quantity) {struct n}: list memval :=
match n with
| O => nil
| S m => Fragment v q m :: inj_value_rec m v q
end.
Definition inj_value (q: quantity) (v: val): list memval :=
inj_value_rec (size_quantity_nat q) v q.
Fixpoint check_value (n: nat) (v: val) (q: quantity) (vl: list memval)
{struct n} : bool :=
match n, vl with
| O, nil => true
| S m, Fragment v' q' m' :: vl' =>
Val.eq v v' && quantity_eq q q' && Nat.eqb m m' && check_value m v q vl'
| _, _ => false
end.
Definition proj_value (q: quantity) (vl: list memval) : val :=
match vl with
| Fragment v q' n :: vl' =>
if check_value (size_quantity_nat q) v q vl then v else Vundef
| _ => Vundef
end.
Definition encode_val (chunk: memory_chunk) (v: val) : list memval :=
match v, chunk with
| Vint n, (Mint8signed | Mint8unsigned) => inj_bytes (encode_int 1%nat (Int.unsigned n))
| Vint n, (Mint16signed | Mint16unsigned) => inj_bytes (encode_int 2%nat (Int.unsigned n))
| Vint n, Mint32 => inj_bytes (encode_int 4%nat (Int.unsigned n))
| Vptr b ofs, Mint32 => if Archi.ptr64 then list_repeat 4%nat Undef else inj_value Q32 v
| Vlong n, Mint64 => inj_bytes (encode_int 8%nat (Int64.unsigned n))
| Vptr b ofs, Mint64 => if Archi.ptr64 then inj_value Q64 v else list_repeat 8%nat Undef
| Vsingle n, Mfloat32 => inj_bytes (encode_int 4%nat (Int.unsigned (Float32.to_bits n)))
| Vfloat n, Mfloat64 => inj_bytes (encode_int 8%nat (Int64.unsigned (Float.to_bits n)))
| _, Many32 => inj_value Q32 v
| _, Many64 => inj_value Q64 v
| _, _ => list_repeat (size_chunk_nat chunk) Undef
end.
Definition decode_val (chunk: memory_chunk) (vl: list memval) : val :=
match proj_bytes vl with
| Some bl =>
match chunk with
| Mint8signed => Vint(Int.sign_ext 8 (Int.repr (decode_int bl)))
| Mint8unsigned => Vint(Int.zero_ext 8 (Int.repr (decode_int bl)))
| Mint16signed => Vint(Int.sign_ext 16 (Int.repr (decode_int bl)))
| Mint16unsigned => Vint(Int.zero_ext 16 (Int.repr (decode_int bl)))
| Mint32 => Vint(Int.repr(decode_int bl))
| Mint64 => Vlong(Int64.repr(decode_int bl))
| Mfloat32 => Vsingle(Float32.of_bits (Int.repr (decode_int bl)))
| Mfloat64 => Vfloat(Float.of_bits (Int64.repr (decode_int bl)))
| Many32 => Vundef
| Many64 => Vundef
end
| None =>
match chunk with
| Mint32 => if Archi.ptr64 then Vundef else Val.load_result chunk (proj_value Q32 vl)
| Many32 => Val.load_result chunk (proj_value Q32 vl)
| Mint64 => if Archi.ptr64 then Val.load_result chunk (proj_value Q64 vl) else Vundef
| Many64 => Val.load_result chunk (proj_value Q64 vl)
| _ => Vundef
end
end.
Ltac solve_encode_val_length :=
match goal with
| [ |- length (inj_bytes _) = _ ] => rewrite length_inj_bytes; solve_encode_val_length
| [ |- length (encode_int _ _) = _ ] => apply encode_int_length
| [ |- length (if ?x then _ else _) = _ ] => destruct x eqn:?; solve_encode_val_length
| _ => reflexivity
end.

(* Specifications: *)
Lemma encode_val_length:
forall chunk v, length(encode_val chunk v) = size_chunk_nat chunk.
Lemma check_inj_value:
forall v q n, check_value n v q (inj_value_rec n v q) = true.
Lemma proj_inj_value:
forall q v, proj_value q (inj_value q v) = v.