1 module grpc.common.byte_buffer;
2 import grpc.logger;
3 import interop.headers;
4 import grpc.core.resource;
5 import grpc.core.sync.mutex;
6 import core.lifetime;
7 
8 struct ByteBuffer {
9 @nogc:
10     private {
11         shared(Mutex) mutex;
12         SharedResource buf;
13         grpc_byte_buffer_reader reader;
14 
15         static bool release(shared(void)* ptr) @trusted nothrow {
16             grpc_byte_buffer** v = cast(grpc_byte_buffer**)ptr;
17             if (v != null) {
18                 if (*v != null) {
19                     grpc_byte_buffer_destroy(*v);
20                 }
21                 gpr_free(cast(void*)v);
22                 v = null;
23             }
24             return true;
25         }
26     }
27 
28     inout(grpc_byte_buffer)** safeHandle() inout @trusted nothrow {
29         return cast(typeof(return)) buf.handle;
30     }
31     
32     inout(grpc_byte_buffer)* handle() inout @trusted nothrow {
33         return cast(typeof(return)) *safeHandle;
34     }
35     
36     bool valid() {
37         return handle != null;
38     }
39 
40     bool compressed() {
41         lock;
42         scope(exit) unlock;
43         
44         assert(valid, "byte buffer was not valid");
45         
46         return handle.type == GRPC_BB_RAW;
47     }
48 
49     ulong length() {
50         lock;
51         scope(exit) unlock;
52         
53         if (!valid) {
54             return 0;
55         } else {
56             return grpc_byte_buffer_length(handle);
57         }
58     }
59     
60     void lock() {
61         DEBUG!"bf lock";
62         mutex.lock;
63     }
64     
65     void unlock() {
66         DEBUG!"bf unlock";
67         mutex.unlock;
68     }
69 
70     auto readAll() {
71         import grpc.core.utils;
72         lock;
73         scope(exit) unlock;
74         
75         assert(valid, "byte buffer was not valid");
76 
77         return byte_buffer_to_type!(ubyte[])(handle);
78     }
79 
80     ubyte[] read() {
81         import grpc.core.utils;
82 
83         lock;
84         scope(exit) unlock;
85         
86         assert(valid, "byte buffer was not valid");
87         
88         if(reader == grpc_byte_buffer_reader.init) {
89             grpc_byte_buffer_reader_init(&reader, handle);
90         }
91 
92         grpc_slice slice;
93         reader.current.index = 0;
94         if(grpc_byte_buffer_reader_next(&reader, &slice) == 0) {
95             grpc_byte_buffer_reader_destroy(&reader);
96             reader = reader.init;
97         }
98         
99         return slice_to_type!(ubyte[])(slice);
100     }
101 
102 
103     static ByteBuffer copy(ByteBuffer obj) {
104         obj.lock;
105         scope(exit) obj.unlock;
106 
107         assert(obj.valid, "byte buffer was not valid");
108         auto buf_2 = grpc_byte_buffer_copy(obj.handle);
109         ByteBuffer ret = ByteBuffer.create();
110         *(ret.safeHandle) = buf_2;
111         return ret;
112     }
113     
114     void cleanup() {
115         lock;
116         scope(exit) unlock;
117         assert(valid, "byte buffer must be valid to clean");
118         grpc_byte_buffer_destroy(handle);
119         *(safeHandle) = null;
120         assert(!valid, "byte buffer must be invalid now");
121     }
122 
123     static ByteBuffer create() @trusted {
124         grpc_byte_buffer** res = cast(grpc_byte_buffer**)gpr_zalloc((void*).sizeof);
125         return ByteBuffer(cast(shared)Mutex.create(), SharedResource(cast(shared)res, &release));
126     }
127 
128 
129     static ByteBuffer create(ref ubyte[] _data) @trusted {
130         import grpc.core.utils;
131         grpc_slice _dat = type_to_slice!(ubyte[])(_data);
132         grpc_byte_buffer** res = cast(grpc_byte_buffer**)gpr_zalloc((void*).sizeof);
133         grpc_byte_buffer* _buf = grpc_raw_byte_buffer_create(&_dat, 1);
134         *res = _buf;
135         return ByteBuffer(cast(shared)Mutex.create(), SharedResource(cast(shared)res, &release));
136     }
137     
138     ~this() {
139         buf.forceRelease();
140     }
141 }