import { Bytes, BytesLike } from "../bytes/index.js";
import { Num, NumLike } from "../num/index.js";
export type CodecLike<Encodable, Decoded = Encodable> = {
    readonly encode: (encodable: Encodable) => Bytes;
    readonly decode: (decodable: BytesLike, config?: {
        isExtraFieldIgnored?: boolean;
    }) => Decoded;
    readonly byteLength?: number;
};
export declare class Codec<Encodable, Decoded = Encodable> {
    readonly encode: (encodable: Encodable) => Bytes;
    readonly decode: (decodable: BytesLike, config?: {
        isExtraFieldIgnored?: boolean;
    }) => Decoded;
    readonly byteLength?: number | undefined;
    constructor(encode: (encodable: Encodable) => Bytes, decode: (decodable: BytesLike, config?: {
        isExtraFieldIgnored?: boolean;
    }) => Decoded, byteLength?: number | undefined);
    static from<Encodable, Decoded = Encodable>({ encode, decode, byteLength, }: CodecLike<Encodable, Decoded>): Codec<Encodable, Decoded>;
    map<NewEncodable = Encodable, NewDecoded = Decoded>({ inMap, outMap, }: {
        inMap?: (encodable: NewEncodable) => Encodable;
        outMap?: (decoded: Decoded) => NewDecoded;
    }): Codec<NewEncodable, NewDecoded>;
    mapIn<NewEncodable>(map: (encodable: NewEncodable) => Encodable): Codec<NewEncodable, Decoded>;
    mapOut<NewDecoded>(map: (decoded: Decoded) => NewDecoded): Codec<Encodable, NewDecoded>;
}
export type EncodableType<T extends CodecLike<any, any>> = T extends CodecLike<infer Encodable, unknown> ? Encodable : never;
export type DecodedType<T extends CodecLike<any, any>> = T extends CodecLike<any, infer Decoded> ? Decoded : never;
/**
 * Vector with fixed size item codec
 * @param itemCodec fixed-size vector item codec
 */
export declare function fixedItemVec<Encodable, Decoded>(itemCodec: CodecLike<Encodable, Decoded>): Codec<Array<Encodable>, Array<Decoded>>;
/**
 * Vector with dynamic size item codec, you can create a recursive vector with this function
 * @param itemCodec the vector item codec. It can be fixed-size or dynamic-size.
 */
export declare function dynItemVec<Encodable, Decoded>(itemCodec: CodecLike<Encodable, Decoded>): Codec<Array<Encodable>, Array<Decoded>>;
/**
 * General vector codec, if `itemCodec` is fixed size type, it will create a fixvec codec, otherwise a dynvec codec will be created.
 * @param itemCodec
 */
export declare function vector<Encodable, Decoded>(itemCodec: CodecLike<Encodable, Decoded>): Codec<Array<Encodable>, Array<Decoded>>;
/**
 * Option is a dynamic-size type.
 * Serializing an option depends on whether it is empty or not:
 * - if it's empty, there is zero bytes (the size is 0).
 * - if it's not empty, just serialize the inner item (the size is same as the inner item's size).
 * @param innerCodec
 */
export declare function option<Encodable, Decoded>(innerCodec: CodecLike<Encodable, Decoded>): Codec<Encodable | undefined | null, Decoded | undefined>;
/**
 * Wrap the encoded value with a fixed-length buffer
 * @param codec
 */
export declare function byteVec<Encodable, Decoded>(codec: CodecLike<Encodable, Decoded>): Codec<Encodable, Decoded>;
export type EncodableRecordOptionalKeys<T extends Record<string, CodecLike<any, any>>> = {
    [K in keyof T]: Extract<EncodableType<T[K]>, undefined> extends never ? never : K;
}[keyof T];
export type EncodableRecord<T extends Record<string, CodecLike<any, any>>> = {
    [key in keyof Pick<T, EncodableRecordOptionalKeys<T>>]+?: EncodableType<T[key]>;
} & {
    [key in keyof Omit<T, EncodableRecordOptionalKeys<T>>]: EncodableType<T[key]>;
};
export type DecodedRecordOptionalKeys<T extends Record<string, CodecLike<any, any>>> = {
    [K in keyof T]: Extract<DecodedType<T[K]>, undefined> extends never ? never : K;
}[keyof T];
export type DecodedRecord<T extends Record<string, CodecLike<any, any>>> = {
    [key in keyof Pick<T, DecodedRecordOptionalKeys<T>>]+?: DecodedType<T[key]>;
} & {
    [key in keyof Omit<T, DecodedRecordOptionalKeys<T>>]: DecodedType<T[key]>;
};
/**
 * Table is a dynamic-size type. It can be considered as a dynvec but the length is fixed.
 * @param codecLayout
 */
export declare function table<T extends Record<string, CodecLike<any, any>>, Encodable extends EncodableRecord<T>, Decoded extends DecodedRecord<T>>(codecLayout: T): Codec<Encodable, Decoded>;
type UnionEncodable<T extends Record<string, CodecLike<any, any>>, K extends keyof T = keyof T> = K extends unknown ? {
    type: K;
    value: EncodableType<T[K]>;
} : never;
type UnionDecoded<T extends Record<string, CodecLike<any, any>>, K extends keyof T = keyof T> = K extends unknown ? {
    type: K;
    value: DecodedType<T[K]>;
} : never;
/**
 * Union is a dynamic-size type.
 * Serializing a union has two steps:
 * - Serialize an item type id in bytes as a 32 bit unsigned integer in little-endian. The item type id is the index of the inner items, and it's starting at 0.
 * - Serialize the inner item.
 * @param codecLayout the union item record
 * @param fields the custom item type id record
 * @example
 * // without custom id
 * union({ cafe: Uint8, bee: Uint8 })
 * // with custom id
 * union({ cafe: Uint8, bee: Uint8 }, { cafe: 0xcafe, bee: 0xbee })
 */
export declare function union<T extends Record<string, CodecLike<any, any>>>(codecLayout: T, fields?: Record<keyof T, number | undefined | null>): Codec<UnionEncodable<T>, UnionDecoded<T>>;
/**
 * Struct is a fixed-size type: all fields in struct are fixed-size and it has a fixed quantity of fields.
 * The size of a struct is the sum of all fields' size.
 * @param codecLayout a object contains all fields' codec
 */
export declare function struct<T extends Record<string, CodecLike<any, any>>, Encodable extends EncodableRecord<T>, Decoded extends DecodedRecord<T>>(codecLayout: T): Codec<Encodable, Decoded>;
/**
 * The array is a fixed-size type: it has a fixed-size inner type and a fixed length.
 * The size of an array is the size of inner type times the length.
 * @param itemCodec the fixed-size array item codec
 * @param itemCount
 */
export declare function array<Encodable, Decoded>(itemCodec: CodecLike<Encodable, Decoded>, itemCount: number): Codec<Array<Encodable>, Array<Decoded>>;
/**
 * Create a codec to deal with fixed LE or BE bytes.
 * @param byteLength
 * @param littleEndian
 */
export declare function uint(byteLength: number, littleEndian?: boolean): Codec<NumLike, Num>;
/**
 * Create a codec to deal with fixed LE or BE bytes.
 * @param byteLength
 * @param littleEndian
 */
export declare function uintNumber(byteLength: number, littleEndian?: boolean): Codec<NumLike, number>;
export {};
//# sourceMappingURL=codec.d.ts.map