33import { Bytes , bytesFrom , BytesLike } from "../bytes/index.js" ;
44
55export type CodecLike < Encodable , Decoded = Encodable > = {
6- readonly encode : ( encodable : Encodable ) => Bytes ;
7- readonly decode : (
8- decodable : BytesLike ,
6+ encode : ( encodable : Encodable ) => BytesLike ;
7+ decode : (
8+ decodable : Bytes ,
99 config ?: { isExtraFieldIgnored ?: boolean } ,
1010 ) => Decoded ;
11- readonly byteLength ?: number ;
11+ from ?: ( ( encoded : Encodable ) => Decoded ) | null ;
12+ byteLength ?: number ;
1213} ;
1314export class Codec < Encodable , Decoded = Encodable > {
1415 constructor (
@@ -17,6 +18,7 @@ export class Codec<Encodable, Decoded = Encodable> {
1718 decodable : BytesLike ,
1819 config ?: { isExtraFieldIgnored ?: boolean } , // This is equivalent to "compatible" in the Rust implementation of Molecule.
1920 ) => Decoded ,
21+ public readonly from : ( encodable : Encodable ) => Decoded ,
2022 public readonly byteLength ?: number , // if provided, treat codec as fixed length
2123 ) { }
2224
@@ -40,53 +42,76 @@ export class Codec<Encodable, Decoded = Encodable> {
4042 }
4143 }
4244
43- static from < Encodable , Decoded = Encodable > ( {
44- encode,
45- decode,
46- byteLength,
47- } : CodecLike < Encodable , Decoded > ) : Codec < Encodable , Decoded > {
45+ static from < Encodable , Decoded = Encodable > (
46+ codecLike : CodecLike < Encodable , Decoded > ,
47+ ) : Codec < Encodable , Decoded > {
48+ const newEncode = function ( encodable : Encodable ) {
49+ const encoded = bytesFrom ( codecLike . encode ( encodable ) ) ;
50+ if (
51+ codecLike . byteLength !== undefined &&
52+ encoded . byteLength !== codecLike . byteLength
53+ ) {
54+ throw new Error (
55+ `Codec.encode: expected byte length ${ codecLike . byteLength } , got ${ encoded . byteLength } ` ,
56+ ) ;
57+ }
58+ return encoded ;
59+ } ;
60+ const newDecode = function (
61+ decodable : BytesLike ,
62+ config ?: { isExtraFieldIgnored ?: boolean } ,
63+ ) {
64+ const decodableBytes = bytesFrom ( decodable ) ;
65+ if (
66+ codecLike . byteLength !== undefined &&
67+ decodableBytes . byteLength !== codecLike . byteLength
68+ ) {
69+ throw new Error (
70+ `Codec.decode: expected byte length ${ codecLike . byteLength } , got ${ decodableBytes . byteLength } ` ,
71+ ) ;
72+ }
73+ return codecLike . decode ( decodableBytes , config ) ;
74+ } ;
4875 return new Codec (
49- ( encodable : Encodable ) => {
50- const encoded = encode ( encodable ) ;
51- if ( byteLength !== undefined && encoded . byteLength !== byteLength ) {
52- throw new Error (
53- `Codec.encode: expected byte length ${ byteLength } , got ${ encoded . byteLength } ` ,
54- ) ;
55- }
56- return encoded ;
57- } ,
58- ( decodable , config ) => {
59- const decodableBytes = bytesFrom ( decodable ) ;
60- if (
61- byteLength !== undefined &&
62- decodableBytes . byteLength !== byteLength
63- ) {
64- throw new Error (
65- `Codec.decode: expected byte length ${ byteLength } , got ${ decodableBytes . byteLength } ` ,
66- ) ;
67- }
68- return decode ( decodable , config ) ;
69- } ,
70- byteLength ,
76+ newEncode ,
77+ newDecode ,
78+ codecLike . from ?. bind ( codecLike ) ??
79+ function ( encodable : Encodable ) {
80+ return newDecode ( newEncode ( encodable ) ) ;
81+ } ,
82+ codecLike . byteLength ,
7183 ) ;
7284 }
7385
7486 map < NewEncodable = Encodable , NewDecoded = Decoded > ( {
7587 inMap,
7688 outMap,
89+ from,
7790 } : {
7891 inMap ?: ( encodable : NewEncodable ) => Encodable ;
7992 outMap ?: ( decoded : Decoded ) => NewDecoded ;
93+ from ?: ( encodable : NewEncodable ) => NewDecoded ;
8094 } ) : Codec < NewEncodable , NewDecoded > {
81- return new Codec (
82- ( encodable ) =>
83- this . encode ( ( inMap ? inMap ( encodable ) : encodable ) as Encodable ) ,
84- ( buffer , config ) =>
85- ( outMap
86- ? outMap ( this . decode ( buffer , config ) )
87- : this . decode ( buffer , config ) ) as NewDecoded ,
88- this . byteLength ,
89- ) ;
95+ const encode = inMap
96+ ? ( encodable : NewEncodable ) => this . encode ( inMap ( encodable ) )
97+ : ( this . encode as unknown as ( encodable : NewEncodable ) => Bytes ) ;
98+ const decode = outMap
99+ ? ( buffer : BytesLike , config ?: { isExtraFieldIgnored ?: boolean } ) =>
100+ outMap ( this . decode ( buffer , config ) )
101+ : ( this . decode as unknown as (
102+ buffer : BytesLike ,
103+ config ?: { isExtraFieldIgnored ?: boolean } ,
104+ ) => NewDecoded ) ;
105+ const newFrom =
106+ from ??
107+ ( ( encodable : NewEncodable ) : NewDecoded => {
108+ const toEncode = ( inMap ? inMap ( encodable ) : encodable ) as Encodable ;
109+ return (
110+ outMap ? outMap ( this . from ( toEncode ) ) : this . from ( toEncode )
111+ ) as NewDecoded ;
112+ } ) ;
113+
114+ return new Codec ( encode , decode , newFrom , this . byteLength ) ;
90115 }
91116
92117 mapIn < NewEncodable > (
0 commit comments