1 /**
2    Adler-32 implementation. This module conforms to the APIs defined in std.digest.
3 */
4 module nxt.digest.adler;
5 
6 public import std.digest;
7 
8 /// Template API Adler32 implementation.
9 struct Adler32
10 {
11 	/// Initializes the digest calculation.
12 	void start() pure nothrow @safe @nogc
13 	{
14 		_a = 1;
15 		_b = 0;
16 		_tlen = moduloInterval;
17 	}
18 
19 	/// Feeds the digest with data.
20 	void put(scope const(ubyte)[] data...) @trusted pure nothrow @nogc
21 	{
22 		foreach (immutable ubyte i; data) {
23 			_a += i;
24 			_b += _a;
25 
26 			--_tlen;
27 			if (_tlen == 0) {
28 				_a %= 65521;
29 				_b %= 65521;
30 				_tlen = moduloInterval;
31 			}
32 		}
33 
34 		if (_tlen != moduloInterval) {
35 			_a %= 65521;
36 			_b %= 65521;
37 		}
38 	}
39 
40 	/// Returns the finished Adler-32 digest. This also calls start to reset the internal state.
41 	ubyte[4] finish() @trusted pure nothrow @nogc
42 	{
43 		import std.bitmanip : nativeToBigEndian;
44 		auto a = _a, b = _b;
45 		start();
46 		return nativeToBigEndian((b << 16) | a);
47 	}
48 
49 private:
50 
51 	uint _a = void, _b = void;
52 	uint _tlen = void;
53 
54 	enum moduloInterval = 5552;
55 }
56 
57 ///
58 unittest {
59 	Adler32 adler;
60 	adler.start();
61 	adler.put(cast(ubyte[]) "abc");
62 	assert(adler.finish() == hexString!"024d0127");
63 	adler.start();
64 	adler.put(cast(ubyte[]) "def");
65 	assert(adler.finish() == hexString!"025F0130");
66 }
67 
68 /// Convenience alias for $(D digest) function in std.digest using the Adler32 implementation.
69 auto adler32Of(T...)(T data) {
70 	return digest!(Adler32, T)(data);
71 }
72 
73 /// OOP API for Adler32.
74 alias Adler32Digest = WrapperDigest!Adler32;
75 
76 ///
77 unittest {
78 	auto adler = new Adler32Digest;
79 	assert(adler.digest("abc") == hexString!"024d0127");
80 }
81 
82 pure nothrow @safe @nogc unittest {
83 	static assert(isDigest!Adler32);
84 
85 	assert(adler32Of("abc") == hexString!"024d0127");
86 	assert(adler32Of("abcdefghijklmnopqrstuvwxyz") == hexString!"90860B20");
87 }
88 
89 version (unittest) {
90 	import std.conv : hexString;
91 }