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 }