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.AnyPointer;
23 
24 import std.string : startsWith;
25 import std.traits;
26 
27 import capnproto.Data;
28 import capnproto.Constants;
29 import capnproto.SegmentBuilder;
30 import capnproto.SegmentReader;
31 import capnproto.Text;
32 import capnproto.WireHelpers;
33 import capnproto.WirePointer;
34 
35 struct AnyPointer
36 {
37 public: //Types.
38 	static struct Reader
39 	{
40 	public: //Methods.
41 		this(const(SegmentReader)* segment, int pointer, int nestingLimit)
42 		{
43 			this.segment = segment;
44 			this.pointer = pointer;
45 			this.nestingLimit = nestingLimit;
46 		}
47 		
48 		bool isNull()
49 		{
50 			return WirePointer.isNull(this.segment.buffer.get!long(this.pointer * Constants.BYTES_PER_WORD));
51 		}
52 		
53 		T.Reader getAs(T)()
54 		{
55 			alias name = fullyQualifiedName!T;
56 			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"))
57 				return WireHelpers.readListPointer!(T.Reader)(cast(SegmentReader*)this.segment, this.pointer, null, 0, T.elementSize, this.nestingLimit);
58 			else
59 				return WireHelpers.readStructPointer!(T.Reader)(cast(SegmentReader*)this.segment, this.pointer, null, 0, this.nestingLimit);
60 			//return factory.fromPointerReader(this.segment, this.pointer, this.nestingLimit);
61 		}
62 	
63 	private: //Variables.
64 		const(SegmentReader)* segment;
65 		int pointer; //Offset in words.
66 		int nestingLimit;
67 	}
68 	
69 	static struct Builder
70 	{
71 	public: //Methods.
72 		this(SegmentBuilder* segment, int pointer)
73 		{
74 			this.segment = segment;
75 			this.pointer = pointer;
76 		}
77 		
78 		bool isNull()
79 		{
80 			return WirePointer.isNull(this.segment.buffer.get!long(this.pointer * Constants.BYTES_PER_WORD));
81 		}
82 		
83 		T.Builder getAs(T)()
84 		{
85 			alias name = fullyQualifiedName!T;
86 			
87 			static if(is(T : Data))
88 				return WireHelpers.getWritableDataPointer(this.pointer, this.segment, null, 0, 0);
89 			else static if(is(T : Text))
90 				return WireHelpers.getWritableTextPointer(this.pointer, this.segment, null, 0, 0);
91 			else static if(name.startsWith("capnproto.DataList") || name.startsWith("capnproto.EnumList") || name.startsWith("capnproto.PrimitiveList") || name.startsWith("capnproto.ListList") || name.startsWith("capnproto.TextList"))
92 				return WireHelpers.getWritableListPointer!(T.Builder)(this.pointer, this.segment, T.elementSize, null, 0);
93 			else static if(name.startsWith("capnproto.StructList"))
94 				return WireHelpers.getWritableStructListPointer!(T.Builder)(this.pointer, this.segment, T.structSize, null, 0);
95 			else
96 				return WireHelpers.getWritableStructPointer!(T.Builder)(this.pointer, this.segment, T.structSize, null, 0);
97 			//return fromPointerBuilder!(T.Builder)(this.segment, this.pointer);
98 		}
99 		
100 		T.Builder initAs(T)()
101 		{
102 			alias name = fullyQualifiedName!T;
103 			static if(is(T : AnyPointer))
104 			{
105 				auto result = T.Builder(this.segment, this.pointer);
106 				result.clear();
107 				return result;
108 			}
109 			else
110 				return WireHelpers.initStructPointer!(T.Builder)(this.pointer, this.segment, T.structSize);
111 			//return T.initFromPointerBuilder(this.segment, this.pointer, 0);
112 		}
113 		
114 		T.Builder initAs(T)(int elementCount)
115 		{
116 			alias name = fullyQualifiedName!T;
117 			
118 			static if(is(T : Data))
119 				return WireHelpers.initDataPointer(this.pointer, this.segment, elementCount);
120 			else static if(is(T : Text))
121 				return WireHelpers.initTextPointer(this.pointer, this.segment, elementCount);
122 			else static if(name.startsWith("capnproto.DataList") || name.startsWith("capnproto.EnumList") || name.startsWith("capnproto.PrimitiveList") || name.startsWith("capnproto.ListList") || name.startsWith("capnproto.TextList"))
123 				return WireHelpers.initListPointer!(T.Builder)(this.pointer, this.segment, elementCount, T.elementSize);
124 			else static if(name.startsWith("capnproto.StructList"))
125 				return WireHelpers.initStructListPointer!(T.Builder)(this.pointer, this.segment, elementCount, T.structSize);
126 			else
127 				return WireHelpers.initStructPointer!(T.Builder)(this.pointer, this.segment, elementCount);
128 		}
129 		
130 		void setAs(T, U)(U reader)
131 		{
132 			alias name = fullyQualifiedName!U;
133 			
134 			static if(is(T : Data))
135 				WireHelpers.setDataPointer(this.pointer, this.segment, reader);
136 			else static if(is(T : Text))
137 				WireHelpers.setTextPointer(this.pointer, this.segment, reader);
138 			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"))
139 				WireHelpers.setListPointer(this.segment, this.pointer, reader.b);
140 			else
141 				WireHelpers.setStructPointer(this.segment, this.pointer, reader.b);
142 			//factory.setPointerBuilder(this.segment, this.pointer, reader);
143 		}
144 		
145 		Reader asReader()
146 		{
147 			return Reader(segment.asReader(), pointer, 0x7fffffff);
148 		}
149 		
150 		void clear()
151 		{
152 			WireHelpers.zeroObject(this.segment, this.pointer);
153 			this.segment.buffer.put!long(this.pointer * 8, 0L);
154 		}
155 	
156 	private: //Variables.
157 		SegmentBuilder* segment;
158 		int pointer;
159 	}
160 }