// Copyright 2024 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
pub suberror DecodingError {
Malformed(Bytes)
Truncated(Bytes)
} derive(Show)
///|
pub impl ToJson for DecodingError with to_json(self : DecodingError) -> Json {
match self {
Malformed(bytes) => { "malformed": bytes.to_array().to_json() }
Truncated(bytes) => { "truncated": bytes.to_array().to_json() }
}
}
///|
pub(all) enum Encoding {
UTF8
UTF16LE
UTF16BE
}
// Decoder
///|
typealias (Decoder) -> Decode as Cont
///|
struct Decoder {
// Input bytes
// Stores the input bytes that need to be decoded.
// The primary data source from which characters are read and decoded.
mut i : FixedArray[Byte]
// Input position
// Keeps track of the current position within the input bytes `i`.
// Indicates the next byte (starting point) to read from `i` during the decoding process
mut i_pos : Int
// Temporary bytes
// Used to temporarily store bytes that are read in parts
// (which might happen for multi-byte encoded characters).
t : FixedArray[Byte]
// Temporary Length
// Tracks how many bytes currently reside in the temporary bytes `t`.
mut t_len : Int
// Temporary Need
// The number of bytes still needed to complete the character code currently being processed.
t_need : Int
// Continuation
// Called with a `Decoder` state.
k : Cont
}
///|
priv enum Decode {
End
Refill(Bytes)
Malformed(Bytes)
Uchar(Char)
}
// helper constructor
///|
fn slice(bytes : FixedArray[Byte], offset : Int, length : Int) -> Bytes {
let new_bytes = FixedArray::make(length, b'0')
bytes.blit_to(new_bytes, len=length, src_offset=offset)
Bytes::from_fixedarray(new_bytes)
}
///|
fn malformed(bytes : FixedArray[Byte], offset : Int, length : Int) -> Decode {
Malformed(slice(bytes, offset, length))
}
///|
fn malformed_pair(
be : Bool,
hi : Int,
bytes : FixedArray[Byte],
offset : Int,
length : Int
) -> Decode {
let bs1 = FixedArray::make(length, Byte::default())
bytes.blit_to(bs1, len=length, src_offset=offset)
let bs0 = FixedArray::make(2, Byte::default())
let (j0, j1) = if be { (0, 1) } else { (1, 0) }
bs0[j0] = (hi >> 8).to_byte()
bs0[j1] = hi.land(0xFF).to_byte()
let bs = @buffer.new(size_hint=bs0.length() + bs1.length())
// specify a known length to skip call method `bs0.length()`
bs.write_bytes(Bytes::from_fixedarray(bs0, len=2))
// ditto
bs.write_bytes(Bytes::from_fixedarray(bs1, len=length))
Malformed(slice(bs.to_bytes().to_fixedarray(), 0, bs.length()))
}