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     ~this()
68     {
69         close();
70     }
71 
72     /// Cleans up the internal ENetPacket.
73     void close()
74     {
75         if(_handle !is null && !_destroyed)
76         {
77             enet_packet_destroy(_handle);
78             _handle = null;
79         }
80     }
81 
82     /**
83      * Resizes the ENetPacket.
84      * Throws: ENetException if the packet cannot be resized
85      * Throws: ENetException if the packet is dirty (has been sent)
86      */
87     void resize(size_t dataLength)
88     {
89         if(!_dirty)
90         {
91             if(dataLength != _handle.dataLength)
92             {
93                 if(dataLength > _largestPacketSize)
94                     _enet._logger.warning("Packet size is larger than underlying data");
95                 
96                 auto errCode = enet_packet_resize(_handle, dataLength);
97                 if(errCode < 0)
98                     throw new ENetException("enet_packet_resize failed");
99             }
100         }
101         else
102         {
103             throw new ENetException("Resizing sent packets is not allowed");
104         }
105     }
106 
107     /// Gets the ENetPacket's data.
108     ubyte[] data()
109     {
110         return _handle.data[0.._handle.dataLength];
111     }
112 
113     /**
114         * Sets the ENetPacket's data.
115         * Throws: ENetException if the packet is dirty (has been sent)
116         * See_Also: resize
117         */
118     void setData(ubyte[] data)
119     {
120         if(!_dirty)
121         {
122             if(data.length > _largestPacketSize)
123                 _largestPacketSize = data.length;
124             resize(data.length);
125             _handle.data = &data[0];
126         }
127         else
128         {
129             throw new ENetException("Changing sent packets is not allowed");
130         }
131     }
132 
133     /// Gets the size of the ENetPacket in bytes.
134     size_t size() pure const nothrow
135     {
136         return _handle.dataLength;
137     }
138 
139     /// Gets application private data.
140     void* userData()
141     {
142         return _handle.userData;
143     }
144 
145     /// Sets application private data.
146     void setUserData(void *newData)
147     {
148         _handle.userData = newData;
149     }
150 }