1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
2 // Licensed under the MIT License:
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 
22 module capnproto.ListReader;
23 
24 import java.nio.ByteBuffer;
25 
26 import capnproto.Constants;
27 import capnproto.Data;
28 import capnproto.ElementSize;
29 import capnproto.SegmentReader;
30 import capnproto.StructReader;
31 import capnproto.Text;
32 import capnproto.WireHelpers;
33 
34 struct ListReader
35 {
36 public: //Methods.
37 	this(SegmentReader* segment, int ptr, int elementCount, int step, int structDataSize, short structPointerCount, int nestingLimit)
38 	{
39 		this.segment = segment;
40 		this.ptr = ptr;
41 		this.elementCount = elementCount;
42 		this.step = step;
43 		this.structDataSize = structDataSize;
44 		this.structPointerCount = structPointerCount;
45 		this.nestingLimit = nestingLimit;
46 	}
47 	
48 	size_t length() const
49 	{
50 		return this.elementCount;
51 	}
52 	
53 	bool _getBooleanElement(size_t index)
54 	{
55 		long bindex = cast(long)index * this.step;
56 		byte b = this.segment.buffer.get!byte(this.ptr + cast(int)(bindex / Constants.BITS_PER_BYTE));
57 		return (b & (1 << (bindex % 8))) != 0;
58 	}
59 	
60 	byte _getByteElement(size_t index)
61 	{
62 		return this.segment.buffer.get!byte(this.ptr + cast(int)(cast(long)index * this.step / Constants.BITS_PER_BYTE));
63 	}
64 	
65 	short _getShortElement(size_t index)
66 	{
67 		return this.segment.buffer.get!short(this.ptr + cast(int)(cast(long)index * this.step / Constants.BITS_PER_BYTE));
68 	}
69 	
70 	int _getIntElement(size_t index)
71 	{
72 		return this.segment.buffer.get!int(this.ptr + cast(int)(cast(long)index * this.step / Constants.BITS_PER_BYTE));
73 	}
74 	
75 	long _getLongElement(size_t index)
76 	{
77 		return this.segment.buffer.get!long(this.ptr + cast(int)(cast(long)index * this.step / Constants.BITS_PER_BYTE));
78 	}
79 	
80 	float _getFloatElement(size_t index)
81 	{
82 		return this.segment.buffer.get!float(this.ptr + cast(int)(cast(long)index * this.step / Constants.BITS_PER_BYTE));
83 	}
84 	
85 	double _getDoubleElement(size_t index)
86 	{
87 		return this.segment.buffer.get!double(this.ptr + cast(int)(cast(long)index * this.step / Constants.BITS_PER_BYTE));
88 	}
89 	
90 	T.Reader _getStructElement(T)(size_t index)
91 	{
92 		//TODO: Check nesting limit.
93 		long indexBit = cast(long)index * this.step;
94 		int structData = this.ptr + cast(int)(indexBit / Constants.BITS_PER_BYTE);
95 		int structPointers = structData + (this.structDataSize / Constants.BITS_PER_BYTE);
96 		return T.Reader(this.segment, structData, structPointers / 8, this.structDataSize, this.structPointerCount, this.nestingLimit - 1);
97 	}
98 	
99 	T.Reader _getPointerElement(T)(size_t index)
100 	{
101 		import std..string : startsWith;
102 		import std.traits;
103 		alias name = fullyQualifiedName!T;
104 		
105 		int pointer = (this.ptr + cast(int)(cast(long)index * this.step / Constants.BITS_PER_BYTE)) / Constants.BYTES_PER_WORD;
106 		static if(is(T : Data))
107 			return WireHelpers.readDataPointer(segment, pointer, null, 0, 0);
108 		else static if(is(T : Text))
109 			return WireHelpers.readTextPointer(segment, pointer, null, 0, 0);
110 		else static if(name.startsWith("capnproto.DataList") || name.startsWith("capnproto.EnumList") || name.startsWith("capnproto.PrimitiveList") || name.startsWith("capnproto.ListList") || name.startsWith("capnproto.StructList") || name.startsWith("capnproto.TextList"))
111 			return WireHelpers.readListPointer!(T.Reader)(this.segment, pointer, null, 0, T.elementSize, this.nestingLimit);
112 		else
113 			return WireHelpers.readStructPointer!(T.Reader)(this.segment, pointer, null, 0, ElementSize.INLINE_COMPOSITE, this.nestingLimit);
114 	}
115 	
116 	T.Reader _getPointerElement(T)(size_t index, ref ByteBuffer defaultBuffer, int defaultOffset, int defaultSize)
117 	{
118 		static if(is(T : Data))
119 			return WireHelpers.readDataPointer(this.segment, (this.ptr + cast(int)(cast(long)index * this.step / Constants.BITS_PER_BYTE)) / Constants.BYTES_PER_WORD, defaultBuffer, defaultOffset, defaultSize);
120 		static if(is(T : Text))
121 			return WireHelpers.readTextPointer(this.segment, (this.ptr + cast(int)(cast(long)index * this.step / Constants.BITS_PER_BYTE)) / Constants.BYTES_PER_WORD, defaultBuffer, defaultOffset, defaultSize);
122 		else
123 			return WireHelpers.readDataPointer(this.segment, (this.ptr + cast(int)(cast(long)index * this.step / Constants.BITS_PER_BYTE)) / Constants.BYTES_PER_WORD, defaultBuffer, defaultOffset, defaultSize);
124 	}
125 
126 package:
127 	SegmentReader* segment;
128 	int ptr; //Byte offset to front of list.
129 	int elementCount;
130 	int step; //In bits.
131 	int structDataSize; //In bits.
132 	short structPointerCount;
133 	int nestingLimit;
134 }