1 /// Provides the Packet class.
2 
3 module gfm.enet.packet;
4 
5 import std.traits : isArray, isScalarType;
6 import derelict.enet.enet;
7 import gfm.enet.enet;
8 
9 
10 /// Encompasses an ENetPacket with an object-oriented wrapper. Once a packet has
11 /// been sent, the data cannot be modified.
12 final class Packet
13 {
14     private size_t _largestPacketSize;
15 
16     package
17     {
18         ENet _enet;
19         ENetPacket *_handle;
20         bool _dirty; // Disallows changing after being sent
21         bool _destroyed; // When ENet internally destroys packet
22     }
23 
24     /**
25      * Creates an ENetPacket internally.
26      * Throws: ENetException when enet_packet_create fails
27      * Params:
28      *     enet = Library object
29      *     data = Initial contents of the packet's data
30      *     dataLength = Size of the data allocated for this packet
31      *     flags = Flags for this packet
32      */
33     this(ENet enet, const(void) *data, size_t dataLength, uint flags=0)
34     {
35         _enet = enet;
36         _handle = enet_packet_create(data, dataLength, flags);
37         if(_handle is null)
38             throw new ENetException("enet_packet_create failed");
39         _largestPacketSize = dataLength;
40         _dirty = false;
41         _destroyed = false;
42     }
43 
44     /// A convenience constructor for an already existing ENetPacket.
45     this(ENet enet, ENetPacket *packet)
46     {
47         _enet = enet;
48         _handle = packet;
49         if(_handle != null)
50             _largestPacketSize = _handle.dataLength;
51         _dirty = false; // Not guaranteed, but trust thy user.
52         _destroyed = false;
53     }
54 
55     /// A convenience constructor for array data.
56     this(T)(ENet enet, T data, uint flags=0) if(isArray!T)
57     {
58         this(enet, &data[0], data.length, flags);
59     }
60 
61     /// A convenience constructor for scalar data.
62     this(T)(ENet enet, T data, uint flags=0) if(isScalarType!T)
63     {
64         this(enet, &data, 1, flags);
65     }
66 
67     /// Cleans up the internal ENetPacket.
68     ~this()
69     {
70         if(_handle !is null && !_destroyed)
71         {
72             debug ensureNotInGC("Packet");
73             enet_packet_destroy(_handle);
74             _handle = null;
75         }
76     }
77 
78     /**
79      * Resizes the ENetPacket.
80      * Throws: ENetException if the packet cannot be resized
81      * Throws: ENetException if the packet is dirty (has been sent)
82      */
83     void resize(size_t dataLength)
84     {
85         if(!_dirty)
86         {
87             if(dataLength != _handle.dataLength)
88             {
89                 if(dataLength > _largestPacketSize)
90                     _enet._logger.warning("Packet size is larger than underlying data");
91 
92                 auto errCode = enet_packet_resize(_handle, dataLength);
93                 if(errCode < 0)
94                     throw new ENetException("enet_packet_resize failed");
95             }
96         }
97         else
98         {
99             throw new ENetException("Resizing sent packets is not allowed");
100         }
101     }
102 
103     /// Gets the ENetPacket's data.
104     ubyte[] data()
105     {
106         return _handle.data[0.._handle.dataLength];
107     }
108 
109     /**
110         * Sets the ENetPacket's data.
111         * Throws: ENetException if the packet is dirty (has been sent)
112         * See_Also: resize
113         */
114     void setData(ubyte[] data)
115     {
116         if(!_dirty)
117         {
118             if(data.length > _largestPacketSize)
119                 _largestPacketSize = data.length;
120             resize(data.length);
121             _handle.data = &data[0];
122         }
123         else
124         {
125             throw new ENetException("Changing sent packets is not allowed");
126         }
127     }
128 
129     /// Gets the size of the ENetPacket in bytes.
130     size_t size() pure const nothrow
131     {
132         return _handle.dataLength;
133     }
134 
135     /// Gets application private data.
136     void* userData()
137     {
138         return _handle.userData;
139     }
140 
141     /// Sets application private data.
142     void setUserData(void *newData)
143     {
144         _handle.userData = newData;
145     }
146 }