@@ -3,6 +3,7 @@ const Allocator = std.mem.Allocator;
33const  Multicodec  =  @import ("multicodec.zig" ).Multicodec ;
44const  Multihash  =  @import ("multihash.zig" ).Multihash ;
55const  varint  =  @import ("unsigned_varint.zig" );
6+ const  MultiBaseCodec  =  @import ("multibase.zig" ).MultiBaseCodec ;
67
78pub  const  Error  =  error {
89    UnknownCodec ,
@@ -48,29 +49,31 @@ pub fn Cid(comptime S: usize) type {
4849        hash : Multihash (S ),
4950        allocator : Allocator ,
5051
51-         pub  fn  newV0 (allocator : Allocator , hash : Multihash (32 )) ! Cid  {
52+         const  Self  =  @This ();
53+ 
54+         pub  fn  newV0 (allocator : Allocator , hash : Multihash (32 )) ! Self  {
5255            if  (hash .getCode () !=  Multicodec .SHA2_256  or  hash .getSize () !=  32 ) {
5356                return  Error .InvalidCidV0Multihash ;
5457            }
5558
56-             return  Cid {
59+             return  Cid ( 32 ) {
5760                .version  =  .V0 ,
5861                .codec  =  Multicodec .DAG_PB .getCode (),
5962                .hash  =  hash ,
6063                .allocator  =  allocator ,
6164            };
6265        }
6366
64-         pub  fn  newV1 (allocator : Allocator , codec : u64 , hash : Multihash (S )) ! Cid  {
65-             return  Cid {
67+         pub  fn  newV1 (allocator : Allocator , codec : u64 , hash : Multihash (S )) ! Self  {
68+             return  Cid ( S ) {
6669                .version  =  .V1 ,
6770                .codec  =  codec ,
6871                .hash  =  hash ,
6972                .allocator  =  allocator ,
7073            };
7174        }
7275
73-         pub  fn  init (allocator : Allocator , version : CidVersion , codec : u64 , hash : Multihash (S )) ! @This ()  {
76+         pub  fn  init (allocator : Allocator , version : CidVersion , codec : u64 , hash : Multihash (S )) ! Self  {
7477            switch  (version ) {
7578                .V0  = >  {
7679                    if  (codec  !=  Multicodec .DAG_PB .getCode ()) {
@@ -85,15 +88,43 @@ pub fn Cid(comptime S: usize) type {
8588            }
8689        }
8790
88-         pub  fn  readBytes (allocator : Allocator , reader : anytype ) ! Cid  {
91+         /// Checks if two CIDs are equal by comparing version, codec and hash 
92+         pub  fn  isEqual (self : * const  Self , other : * const  Self ) bool  {
93+             return  self .version  ==  other .version  and 
94+                 self .codec  ==  other .codec  and 
95+                 std .mem .eql (u8 , self .hash .getDigest (), other .hash .getDigest ());
96+         }
97+ 
98+         pub  fn  writeBytesV1 (self : * const  Self , writer : anytype ) ! usize  {
99+             const  version_written  =  try  varint .encode_stream (writer , u64 , self .version .toInt ());
100+             const  codec_written  =  try  varint .encode_stream (writer , u64 , self .codec );
101+ 
102+             var  written : usize  =  version_written  +  codec_written ;
103+             written  +=  try  self .hash .write (writer );
104+             return  written ;
105+         }
106+ 
107+         pub  fn  intoV1 (self : Self ) ! Self  {
108+             return  switch  (self .version ) {
109+                 .V0  = >  {
110+                     if  (self .codec  !=  @intFromEnum (Multicodec .DAG_PB )) {
111+                         return  Error .InvalidCidV0Codec ;
112+                     }
113+                     return  newV1 (self .allocator , self .codec , self .hash );
114+                 },
115+                 .V1  = >  self ,
116+             };
117+         }
118+ 
119+         pub  fn  readBytes (allocator : Allocator , reader : anytype ) ! Self  {
89120            const  version  =  try  varint .decode_stream (reader , u64 );
90121            const  codec  =  try  varint .decode_stream (reader , u64 );
91122
92-             // CIDv0 has the fixed `0x12 0x20` prefix 
93123            if  (version  ==  0x12  and  codec  ==  0x20 ) {
94124                var  digest : [32 ]u8  =  undefined ;
95125                try  reader .readNoEof (& digest );
96-                 const  mh  =  try  Multihash (32 ).wrap (version , & digest );
126+                 const  version_codec  =  try  Multicodec .fromCode (version );
127+                 const  mh  =  try  Multihash (32 ).wrap (version_codec , & digest );
97128                return  newV0 (allocator , mh );
98129            }
99130
@@ -102,123 +133,129 @@ pub fn Cid(comptime S: usize) type {
102133                .V0  = >  return  Error .InvalidExplicitCidV0 ,
103134                .V1  = >  {
104135                    const  mh  =  try  Multihash (32 ).read (reader );
105-                     return  Cid .init (allocator , ver , codec , mh . getDigest () );
136+                     return  Self .init (allocator , ver , codec , mh );
106137                },
107138            }
108139        }
109140
110-         fn  writeBytesV1 (self : * const  Cid , writer : anytype ) ! usize  {
111-             const  version_written = try  varint .encode_stream (writer ,u64 ,self .version .toInt ());
112-             const  codec_written = try  varint .encode_stream (writer ,u64 ,self .codec );
141+         pub  fn  writeBytes (self : * const  Self , writer : anytype ) ! usize  {
142+             return  switch  (self .version ) {
143+                 .V0  = >  try  self .hash .write (writer ),
144+                 .V1  = >  try  self .writeBytesV1 (writer ),
145+             };
146+         }
113147
114-             const  written : usize  =  version_written  +  codec_written ;
148+         pub  fn  encodedLen (self : Self ) usize  {
149+             return  switch  (self .version ) {
150+                 .V0  = >  self .hash .encodedLen (),
151+                 .V1  = >  {
152+                     var  version_buf : [varint .bufferSize (u64 )]u8  =  undefined ;
153+                     const  version  =  varint .encode (u64 , self .version .toInt (), & version_buf );
115154
116-             return  written ;
155+                     var  codec_buf : [varint .bufferSize (u64 )]u8  =  undefined ;
156+                     const  codec  =  varint .encode (u64 , self .codec , & codec_buf );
157+ 
158+                     return  version .len  +  codec .len  +  self .hash .encodedLen ();
159+                 },
160+             };
161+         }
162+ 
163+         pub  fn  toBytes (self : * const  Self ) ! []u8  {
164+             var  bytes  =  std .ArrayList (u8 ).init (self .allocator );
165+             errdefer  bytes .deinit ();
166+ 
167+             const  written  =  try  self .writeBytes (bytes .writer ());
168+             std .debug .assert (written  ==  bytes .items .len );
169+ 
170+             return  bytes .toOwnedSlice ();
171+         }
172+ 
173+         pub  fn  getHash (self : * const  Self ) []const  u8  {
174+             return  self .hash .getDigest ();
117175        }
118176
177+         pub  fn  getCodec (self : * const  Self ) u64  {
178+             return  self .codec ;
179+         }
180+ 
181+         pub  fn  getVersion (self : * const  Self ) CidVersion  {
182+             return  self .version ;
183+         }
184+ 
185+         fn  toStringV0 (self : * const  Self ) ! []const  u8  {
186+             const  hash_bytes  =  try  self .hash .toBytes ();
187+             var  bytes  =  std .ArrayList (u8 ).init (self .allocator );
188+             errdefer  bytes .deinit ();
189+             return  MultiBaseCodec .Base58Btc .encode (bytes .items , hash_bytes );
190+         }
191+ 
192+         fn  to_string_v1 (self : * const  Self ) ! []u8  {
193+             const  bytes  =  try  self .toBytes (self .allocator );
194+             defer  self .allocator .free (bytes );
195+ 
196+             const  dest  =  std .ArrayList (u8 ).init (self .allocator );
197+             return  MultiBaseCodec .Base32Lower .encode (dest .items , bytes );
198+         }
119199    };
120200}
121201
122- // test "CID basic operations" { 
123- //     const testing = std.testing; 
124- //     const allocator = testing.allocator; 
125- // 
126- //     // Test CIDv0 
127- //     { 
128- //         var hash = [_]u8{ 0x12, 0x20 } ++ [_]u8{1} ** 32; 
129- //         var cid = try Cid.init(allocator, .V0, .DagPb, hash[2..]); 
130- //         defer cid.deinit(); 
131- // 
132- //         try testing.expect(cid.version == .V0); 
133- //         try testing.expect(cid.codec == .DagPb); 
134- //         try testing.expectEqualSlices(u8, hash[2..], cid.hash); 
135- // 
136- //         // Test toBytes 
137- //         const bytes = try cid.toBytes(); 
138- //         defer allocator.free(bytes); 
139- //         try testing.expectEqualSlices(u8, &hash, bytes); 
140- //     } 
141- // 
142- //     // Test CIDv1 
143- //     { 
144- //         var hash = [_]u8{1} ** 32; 
145- //         var cid = try Cid.init(allocator, .V1, .DagCbor, &hash); 
146- //         defer cid.deinit(); 
147- // 
148- //         try testing.expect(cid.version == .V1); 
149- //         try testing.expect(cid.codec == .DagCbor); 
150- //         try testing.expectEqualSlices(u8, &hash, cid.hash); 
151- //     } 
152- // } 
153- // 
154- // test "CID fromBytes" { 
155- //     const testing = std.testing; 
156- //     const allocator = testing.allocator; 
157- // 
158- //     // Test CIDv0 parsing 
159- //     { 
160- //         var input = [_]u8{ 0x12, 0x20 } ++ [_]u8{1} ** 32; 
161- //         var cid = try Cid.fromBytes(allocator, &input); 
162- //         defer cid.deinit(); 
163- // 
164- //         try testing.expect(cid.version == .V0); 
165- //         try testing.expect(cid.codec == .DagPb); 
166- //         try testing.expectEqualSlices(u8, input[2..], cid.hash); 
167- //     } 
168- // 
169- //     // Test CIDv1 parsing 
170- //     { 
171- //         var input = [_]u8{ 1, @intFromEnum(Codec.DagCbor) } ++ [_]u8{1} ** 32; 
172- //         var cid = try Cid.fromBytes(allocator, &input); 
173- //         defer cid.deinit(); 
174- // 
175- //         try testing.expect(cid.version == .V1); 
176- //         try testing.expect(cid.codec == .DagCbor); 
177- //         try testing.expectEqualSlices(u8, input[2..], cid.hash); 
178- //     } 
179- // } 
180- // 
181- // test "CID error cases" { 
182- //     const testing = std.testing; 
183- //     const allocator = testing.allocator; 
184- // 
185- //     // Test invalid V0 codec 
186- //     { 
187- //         var hash = [_]u8{1} ** 32; 
188- //         try testing.expectError(Error.InvalidCidV0Codec, Cid.init(allocator, .V0, .DagCbor, &hash)); 
189- //     } 
190- // 
191- //     // Test input too short 
192- //     { 
193- //         var input = [_]u8{1}; 
194- //         try testing.expectError(Error.InputTooShort, Cid.fromBytes(allocator, &input)); 
195- //     } 
196- // 
197- //     // Test unknown codec 
198- //     { 
199- //         var input = [_]u8{ 1, 0xFF } ++ [_]u8{1} ** 32; 
200- //         try testing.expectError(Error.UnknownCodec, Cid.fromBytes(allocator, &input)); 
201- //     } 
202- // } 
203- // 
204- // test "CID version checks" { 
205- //     const testing = std.testing; 
206- // 
207- //     // Test V0 string detection 
208- //     { 
209- //         const v0_str = "QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n"; 
210- //         try testing.expect(CidVersion.isV0Str(v0_str)); 
211- // 
212- //         const invalid_str = "invalid"; 
213- //         try testing.expect(!CidVersion.isV0Str(invalid_str)); 
214- //     } 
215- // 
216- //     // Test V0 binary detection 
217- //     { 
218- //         var valid_bytes = [_]u8{ 0x12, 0x20 } ++ [_]u8{1} ** 32; 
219- //         try testing.expect(CidVersion.isV0Binary(&valid_bytes)); 
220- // 
221- //         var invalid_bytes = [_]u8{ 0x00, 0x00 } ++ [_]u8{1} ** 32; 
222- //         try testing.expect(!CidVersion.isV0Binary(&invalid_bytes)); 
223- //     } 
224- // } 
202+ test  "Cid"  {
203+     const  testing  =  std .testing ;
204+     const  allocator  =  testing .allocator ;
205+ 
206+     // Test CIDv0 
207+     {
208+         const  hash  =  try  Multihash (32 ).wrap (Multicodec .SHA2_256 , &[_ ]u8 {0 } **  32 );
209+         const  cid  =  try  Cid (32 ).newV0 (allocator , hash );
210+         try  testing .expectEqual (cid .version , .V0 );
211+         try  testing .expectEqual (cid .codec , Multicodec .DAG_PB .getCode ());
212+     }
213+ 
214+     // Test CIDv1 
215+     {
216+         const  hash  =  try  Multihash (64 ).wrap (Multicodec .SHA2_256 , &[_ ]u8 {0 } **  32 );
217+         const  cid  =  try  Cid (64 ).newV1 (allocator , Multicodec .RAW .getCode (), hash );
218+         try  testing .expectEqual (cid .version , .V1 );
219+         try  testing .expectEqual (cid .codec , Multicodec .RAW .getCode ());
220+     }
221+ 
222+     // Test encoding/decoding 
223+     {
224+         const  hash  =  try  Multihash (32 ).wrap (Multicodec .SHA2_256 , &[_ ]u8 {0 } **  32 );
225+         const  original  =  try  Cid (32 ).newV1 (allocator , Multicodec .RAW .getCode (), hash );
226+ 
227+         const  bytes  =  try  original .toBytes ();
228+         defer  allocator .free (bytes );
229+ 
230+         var  fbs  =  std .io .fixedBufferStream (bytes );
231+         const  decoded  =  try  Cid (32 ).readBytes (allocator , fbs .reader ());
232+ 
233+         try  testing .expect (original .isEqual (& decoded ));
234+     }
235+ }
236+ 
237+ test  "Cid conversion and comparison"  {
238+     const  testing  =  std .testing ;
239+     const  allocator  =  testing .allocator ;
240+ 
241+     // Test V0 to V1 conversion 
242+     {
243+         const  hash  =  try  Multihash (32 ).wrap (Multicodec .SHA2_256 , &[_ ]u8 {0 } **  32 );
244+         const  v0  =  try  Cid (32 ).newV0 (allocator , hash );
245+         const  v1  =  try  v0 .intoV1 ();
246+ 
247+         try  testing .expectEqual (v1 .version , .V1 );
248+         try  testing .expectEqual (v1 .codec , v0 .codec );
249+         try  testing .expect (std .mem .eql (u8 , v1 .getHash (), v0 .getHash ()));
250+     }
251+ 
252+     // Test encoded length 
253+     {
254+         const  hash  =  try  Multihash (32 ).wrap (Multicodec .SHA2_256 , &[_ ]u8 {0 } **  32 );
255+         const  cid  =  try  Cid (32 ).newV1 (allocator , Multicodec .RAW .getCode (), hash );
256+         const  bytes  =  try  cid .toBytes ();
257+         defer  allocator .free (bytes );
258+ 
259+         try  testing .expectEqual (cid .encodedLen (), bytes .len );
260+     }
261+ }
0 commit comments