Skip to content

Commit bcc4fed

Browse files
committed
Linq support.
1 parent ca37cac commit bcc4fed

File tree

8 files changed

+1155
-0
lines changed

8 files changed

+1155
-0
lines changed

Luaon.NET/Linq/LField.cs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Diagnostics;
4+
using System.Text;
5+
6+
namespace Luaon.Linq
7+
{
8+
public class LField : LToken
9+
{
10+
private LToken _Value;
11+
12+
/// <summary>
13+
/// Initializes a new positional Lua table field with the specified name and value.
14+
/// </summary>
15+
/// <inheritdoc cref="LField(LValue,LToken)"/>
16+
public LField(LToken value) : this(null, value)
17+
{
18+
}
19+
20+
/// <summary>
21+
/// Initializes a new Lua table field with the specified name and value.
22+
/// </summary>
23+
/// <param name="name">Name of the field. Use <c>null</c> for positional field.</param>
24+
/// <param name="value">Value of the field. Can be <c>null</c>, which means <see cref="LValue.Nil"/>.</param>
25+
/// <exception cref="ArgumentException"><paramref name="name"/>.<see cref="LValue.TokenType"/> is <see cref="LTokenType.Nil"/>.</exception>
26+
public LField(LValue name, LToken value)
27+
{
28+
if (name != null && name.TokenType == LTokenType.Nil)
29+
throw new ArgumentException("Cannot use nil as field name.");
30+
Name = name;
31+
_Value = value ?? LValue.Nil;
32+
}
33+
34+
// Though Lua even allows table expressions as keys, it's pointless in serialization.
35+
/// <summary>
36+
/// Gets the name of the Lua table field.
37+
/// </summary>
38+
/// <value>The field name, or <c>null</c> for field without explict field name.</value>
39+
public LValue Name { get; }
40+
41+
/// <summary>
42+
/// Gets/sets the value of the Lua table field.
43+
/// </summary>
44+
public LToken Value
45+
{
46+
get { return _Value; }
47+
set
48+
{
49+
if (value != null && value.TokenType == LTokenType.Field)
50+
throw new ArgumentException("Cannot set value to LField instance.");
51+
_Value = value ?? LValue.Nil;
52+
}
53+
}
54+
55+
/// <inheritdoc />
56+
public override LTokenType TokenType => LTokenType.Field;
57+
58+
/// <inheritdoc />
59+
public override void WriteTo(LuaTableTextWriter writer)
60+
{
61+
if (Name != null)
62+
{
63+
switch (Name.TokenType)
64+
{
65+
case LTokenType.Boolean:
66+
writer.WriteKey((bool)Name);
67+
break;
68+
case LTokenType.Integer:
69+
writer.WriteKey((long)Name);
70+
break;
71+
case LTokenType.Float:
72+
writer.WriteKey((double)Name);
73+
break;
74+
case LTokenType.String:
75+
writer.WriteKey((string)Name);
76+
break;
77+
default:
78+
Debug.Fail("Invalid Name.TokenType.");
79+
break;
80+
}
81+
}
82+
Value.WriteTo(writer);
83+
}
84+
85+
/// <inheritdoc />
86+
public override LToken DeepClone()
87+
{
88+
return new LField(Name, Value);
89+
}
90+
}
91+
}

Luaon.NET/Linq/LTable.cs

Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Diagnostics;
5+
using System.Linq;
6+
using System.Text;
7+
8+
namespace Luaon.Linq
9+
{
10+
/// <summary>
11+
/// Represents a table in Lua.
12+
/// </summary>
13+
/// <remarks>See <a herf="http://www.lua.org/manual/5.3/manual.html#2.1">2.1 Values and Types</a> for the basic concepts on Lua tables.</remarks>
14+
public class LTable : LToken, ICollection<LField>
15+
{
16+
17+
private readonly LTableStore store = new LTableStore();
18+
19+
public LTable()
20+
{
21+
22+
}
23+
24+
public LTable(IEnumerable<object> content)
25+
{
26+
foreach (var i in content) Add(i);
27+
}
28+
29+
public LTable(params object[] content)
30+
{
31+
foreach (var i in content) Add(i);
32+
}
33+
34+
/// <summary>
35+
/// Inserts a field at the end of the table expression.
36+
/// </summary>
37+
/// <param name="field">The new field to be appended.</param>
38+
/// <exception cref="ArgumentNullException"><paramref name="field"/> is <c>null</c>.</exception>
39+
public void Add(LField field)
40+
{
41+
if (field == null) throw new ArgumentNullException(nameof(field));
42+
store.Add(field);
43+
}
44+
45+
/// <summary>
46+
/// Inserts a new positional field at the end of the table expression.
47+
/// </summary>
48+
/// <param name="value">The value of the new field to be appended. <c>null</c> will be treated the same as <see cref="LValue.Nil"/>.</param>
49+
public void Add(LToken value)
50+
{
51+
Add(null, value);
52+
}
53+
54+
/// <summary>
55+
/// Inserts a field at the end of the table expression.
56+
/// </summary>
57+
/// <param name="name">The name of the new field to be appended.</param>
58+
/// <param name="value">The value of the new field to be appended. <c>null</c> will be treated the same as <see cref="LValue.Nil"/>.</param>
59+
public void Add(LValue name, LToken value)
60+
{
61+
store.Add(new LField(name, value));
62+
}
63+
64+
/// <summary>
65+
/// Inserts a field or value at the end of the table expression.
66+
/// </summary>
67+
/// <param name="content">The field or value of the field.</param>
68+
public void Add(object content)
69+
{
70+
if (content is LField field)
71+
{
72+
Add(field);
73+
}
74+
else if (content is LToken value)
75+
{
76+
Add(value);
77+
}
78+
else
79+
{
80+
var tv = new LValue(content);
81+
Add(tv);
82+
}
83+
}
84+
85+
/// <inheritdoc />
86+
public void Clear()
87+
{
88+
store.Clear();
89+
}
90+
91+
/// <inheritdoc />
92+
bool ICollection<LField>.Contains(LField item)
93+
{
94+
return store.Contains(item);
95+
}
96+
97+
/// <inheritdoc />
98+
public void CopyTo(LField[] array, int arrayIndex)
99+
{
100+
store.CopyTo(array, arrayIndex);
101+
}
102+
103+
/// <inheritdoc />
104+
public bool Remove(LField item)
105+
{
106+
return store.Remove(item);
107+
}
108+
109+
/// <summary>
110+
/// Removes a field from table by its field name.
111+
/// </summary>
112+
/// <param name="name">Field name.</param>
113+
/// <returns>Whether a matching item has been removed.</returns>
114+
/// <remarks>To remvoe a positional field, pass a numeric value to the <paramref name="name"/> parameter.</remarks>
115+
public bool Remove(LValue name)
116+
{
117+
return store.RemoveByName(name);
118+
}
119+
120+
/// <summary>
121+
/// Removes a field from table by its field name.
122+
/// </summary>
123+
/// <param name="name">Field name.</param>
124+
/// <returns>Whether a matching item has been removed.</returns>
125+
public bool Remove(int name)
126+
{
127+
// TODO remvoe by int, rather than LValue
128+
return store.RemoveByName(name);
129+
}
130+
131+
/// <inheritdoc />
132+
public int Count => store.Count;
133+
134+
/// <inheritdoc />
135+
bool ICollection<LField>.IsReadOnly => false;
136+
137+
/// <summary>
138+
/// Inserts an element at the specified position <paramref name="index"/> in the table expression.
139+
/// </summary>
140+
/// <param name="index">The position to insert the value.</param>
141+
/// <param name="item">The new value to be inserted.</param>
142+
/// <exception cref="ArgumentOutOfRangeException"><paramref name="index"/> is less than 0 or greater than <see cref="Count"/>.</exception>
143+
public void Insert(int index, LField item)
144+
{
145+
store.Insert(index, item);
146+
}
147+
148+
/// <summary>
149+
/// Removes the field element at the specified document position.
150+
/// </summary>
151+
/// <param name="index">The position to remove the value.</param>
152+
/// <exception cref="ArgumentOutOfRangeException"><paramref name="index"/> is less than 0 or greater than or equal to <see cref="Count"/>.</exception>
153+
/// <remarks>The index pos can also be 0 when #list is 0, or #list + 1; in those cases, the function erases the element list[pos].</remarks>
154+
public void RemoveAt(int index)
155+
{
156+
store.RemoveAt(index);
157+
}
158+
159+
/// <summary>
160+
/// Gets/sets the field value associated with the specified field key.
161+
/// </summary>
162+
/// <param name="name">The key of the field to set or get.</param>
163+
/// <returns>The value of the specified field, or <c>null</c> if the field does not exist.</returns>
164+
public override LToken this[int name]
165+
{
166+
get { return store.FieldFromName(name, null, false)?.Value; }
167+
set { store.FieldFromName(name, null, true).Value = value; }
168+
}
169+
170+
/// <summary>
171+
/// Gets/sets the field value associated with the specified field key.
172+
/// </summary>
173+
/// <param name="name">The key of the field to set or get.</param>
174+
/// <returns>The value of the specified field, or <c>null</c> if the field does not exist.</returns>
175+
public override LToken this[string name]
176+
{
177+
get { return store.FieldFromName(name, false)?.Value; }
178+
set { store.FieldFromName(name, true).Value = value; }
179+
}
180+
181+
/// <summary>
182+
/// Gets/sets the field value associated with the specified field key.
183+
/// </summary>
184+
/// <param name="name">The key of the field to set or get.</param>
185+
/// <returns>The value of the specified field, or <c>null</c> if the field does not exist.</returns>
186+
public override LToken this[LValue name]
187+
{
188+
get { return store.FieldFromName(name, false)?.Value; }
189+
set { store.FieldFromName(name, true).Value = value; }
190+
}
191+
192+
/// <summary>
193+
/// Tries to get the field instance with the specified field name.
194+
/// </summary>
195+
/// <param name="name">The field name.</param>
196+
/// <returns>The field instance, or <c>null</c> if no matching field exists.</returns>
197+
public LField Field(LValue name)
198+
{
199+
return store.FieldFromName(name, false);
200+
}
201+
202+
/// <summary>
203+
/// Tries to get the field instance with the specified field name.
204+
/// </summary>
205+
/// <param name="name">The field name.</param>
206+
/// <returns>The field instance, or <c>null</c> if no matching field exists.</returns>
207+
public LField Field(int name)
208+
{
209+
return store.FieldFromName(name, null, false);
210+
}
211+
212+
/// <summary>
213+
/// Tries to get the field instance with the specified field name.
214+
/// </summary>
215+
/// <param name="name">The field name.</param>
216+
/// <returns>The field instance, or <c>null</c> if no matching field exists.</returns>
217+
public LField Field(string name)
218+
{
219+
return store.FieldFromName(name, false);
220+
}
221+
222+
/// <summary>
223+
/// Tries to get the field instance with the specified positional index.
224+
/// </summary>
225+
/// <param name="index">The in-document postion of the field.</param>
226+
/// <returns>The field instance.</returns>
227+
/// <exception cref="IndexOutOfRangeException"><paramref name="index"/> is less than 0 or greater than or equal to <see cref="Count"/>.</exception>
228+
public LField FieldAt(int index)
229+
{
230+
return store[index];
231+
}
232+
233+
/// <summary>
234+
/// Gets a sequence containing all the names of the fields.
235+
/// </summary>
236+
public IEnumerable<LValue> FieldNames() => store.Names();
237+
238+
/// <summary>
239+
/// Gets a sequence containing all the values of the fields.
240+
/// </summary>
241+
public IEnumerable<LToken> FieldValues() => store.Values();
242+
243+
/// <inheritdoc />
244+
public override LTokenType TokenType => LTokenType.Table;
245+
246+
/// <inheritdoc />
247+
public override void WriteTo(LuaTableTextWriter writer)
248+
{
249+
writer.WriteStartTable();
250+
foreach (var field in store)
251+
{
252+
field.WriteTo(writer);
253+
}
254+
writer.WriteEndTable();
255+
}
256+
257+
/// <inheritdoc />
258+
public override LToken DeepClone()
259+
{
260+
var table = new LTable(store.Select(t => t.DeepClone()));
261+
return table;
262+
}
263+
264+
/// <inheritdoc />
265+
public IEnumerator<LField> GetEnumerator()
266+
{
267+
return store.GetEnumerator();
268+
}
269+
270+
/// <inheritdoc />
271+
IEnumerator IEnumerable.GetEnumerator()
272+
{
273+
return GetEnumerator();
274+
}
275+
}
276+
}

0 commit comments

Comments
 (0)