1 module vfile;
2 
3 import core.stdc.stdlib;
4 import core.stdc.string : memcpy;
5 import std.stdio;
6 
7 /**
8  * Implements the virtual file.
9  */
10 public struct VFile{
11 	enum Orientation { unknown, narrow, wide }
12 	private void[] datastream;
13 	private size_t position;
14 	private string name;			///mostly a placeholder, but can be set if needed
15 
16 	/**
17 	 * Creates a virtual file out from an array.
18 	 */
19 	public this(T)(ref T[] target, string name = null){
20 		datastream = cast(void[])target;
21 		this.name = name;
22 	}
23 	/**
24 	 * Creates a virtual file out from a pointer and a length indicator.
25 	 */
26 	public this(void* ptr, size_t length, string name = null){
27 		datastream = ptr[0..length];
28 		this.name = name;
29 	}
30 	/**
31 	 * Indicates if the virtual file is opened.
32 	 * If the datastream isn't null, it must be open.
33 	 */
34 	public @safe @property @nogc bool isOpen(){
35 		return datastream !is null;
36 	}
37 	/**
38 	 * Closes the datastream.
39 	 */
40 	public @safe void close(){
41 		datastream = null;
42 	}
43 	/**
44 	 * Copies the data into the buffer and moves the file forward the length of the buffer.
45 	 * Returns null if EOF is reached.
46 	 */
47 	public T[] rawRead(T)(T[] buffer){
48 		const size_t remaining = datastream.length - position;
49 		if(position + buffer.length <= datastream.length){
50 			memcpy(buffer.ptr, datastream.ptr + position, buffer.length * T.sizeof);
51 			position += buffer.length * T.sizeof;
52 			return buffer;
53 		}else{
54 			return null;
55 		}
56 	}
57 	/**
58 	 * Reads a single element from the stream.
59 	 * Throws Exception if EOF reached.
60 	 * Important: Does not provide any complex serialization method, so structs must avoid heap managed fields like dynamic
61 	 * arrays. They should implement a custom serializer.
62 	 */
63 	public T read(T)(){
64 		T buffer;
65 		if(remaining + T.sizeof <= datastream.length){
66 			memcpy(&buffer, datastream.ptr + position, T.sizeof);
67 			position += T.sizeof;
68 			return buffer;
69 		}else{
70 			throw new Exception("EOF has been reached");
71 		}
72 	}
73 	/**
74 	 * Writes data into the datastream.
75 	 * If the stream is shorter, then it'll be extended.
76 	 */
77 	public void rawWrite(T)(T[] buffer){
78 		if(position + buffer.length >= datastream.length){
79 			datastream.length = position;
80 			datastream.length += buffer.length;
81 		}
82 		memcpy(datastream.ptr + position, buffer.ptr, buffer.length * T.sizeof);
83 		position += buffer.length;
84 		assert(position <= datastream.length);
85 	}
86 	/**
87 	 * Writes a single element to the stream.
88 	 * Throws Exception if EOF reached.
89 	 * Important: Does not provide any complex serialization method, so structs must avoid heap managed fields like dynamic
90 	 * arrays. They should implement a custom serializer.
91 	 */
92 	public T write(T)(T buffer){
93 		if(remaining + T.sizeof <= datastream.length){
94 			memcpy(datastream.ptr + position, &buffer, T.sizeof);
95 			position += T.sizeof;
96 			return buffer;
97 		}else{
98 			throw new Exception("EOF has been reached");
99 		}
100 	}
101 	/**
102 	 * Jumps to the given location.
103 	 */
104 	@nogc @property public void seek(long offset, int origin = SEEK_SET) @trusted{
105 		final switch(origin){
106 			case SEEK_SET:
107 				position = cast(sizediff_t)offset;
108 				break;
109 			case SEEK_CUR:
110 				position += cast(sizediff_t)offset;
111 				break;
112 			case SEEK_END:
113 				position = datastream.length + cast(sizediff_t)offset;
114 				break;
115 		}
116 		position = position > datastream.length ? datastream.length : position;
117 	}
118 	/**
119 	 * Returns the current position.
120 	 */
121 	@nogc @property public size_t tell(){
122 		return position;
123 	}
124 	/**
125 	 * Returns the size of the datastream.
126 	 */
127 	@nogc @property public size_t size(){
128 		return datastream.length;
129 	}
130 
131 }
132 unittest{
133 	immutable string a = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum et libero dignissim, porta odio id, 
134 			sollicitudin quam. Suspendisse ultrices quis erat nec elementum. Phasellus sollicitudin vehicula nunc, vel 
135 			laoreet magna dictum eget. Pellentesque sit amet tellus ac mauris elementum bibendum sed in eros. Nullam nec ligula 
136 			id ligula egestas malesuada. Etiam et nulla nec nibh faucibus suscipit non id felis. Integer vulputate lobortis 
137 			neque, ut congue nisl suscipit at. Nullam ac ante eu orci viverra dapibus. \n";
138 	immutable string b = "Vivamus quis finibus mi. Proin lectus enim, convallis a libero a, condimentum eleifend nisl. Vestibulum 
139 			luctus malesuada orci a ornare. Curabitur orci dolor, ultricies ut malesuada nec, semper dictum justo. Ut vestibulum 
140 			nisl id velit congue, tristique porta sapien rutrum. Pellentesque ultricies id arcu non fermentum. Ut at est ex. Sed 
141 			elementum gravida risus, et cursus magna tincidunt nec. Morbi hendrerit efficitur neque, non ultricies quam maximus 
142 			in. Sed bibendum bibendum dui, egestas dignissim orci tincidunt porta. Sed nec aliquet leo, eu posuere massa. \n";
143 	string s;
144 	VFile file = VFile(s);
145 	file.rawWrite(a);
146 	file.rawWrite(b);
147 	assert(file.size == a.length + b.length);
148 	char[] c;
149 	c.length = a.length + b.length;
150 	file.seek(0);
151 	file.rawRead(c);
152 	assert(c == a ~ b);
153 	file.seek(0);
154 	c.length = 5;
155 	file.rawRead(c);
156 	assert(c == "Lorem");
157 }