Skip to content

Commit e91b8ba

Browse files
committed
improve the ini serializer
1 parent abc29ac commit e91b8ba

18 files changed

+670
-377
lines changed

extensions/Sisk.IniConfiguration/IniDocument.cs extensions/Sisk.IniConfiguration.Core/IniDocument.cs

+31-22
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,7 @@
1-
// The Sisk Framework source code
2-
// Copyright (c) 2024- PROJECT PRINCIPIUM and all Sisk contributors
3-
//
4-
// The code below is licensed under the MIT license as
5-
// of the date of its publication, available at
6-
//
7-
// File name: IniDocument.cs
8-
// Repository: https://github.com/sisk-http/core
1+
using System.Text;
2+
using Sisk.IniConfiguration.Core.Serialization;
93

10-
using System.Text;
11-
using Sisk.IniConfiguration.Serializer;
12-
13-
namespace Sisk.IniConfiguration;
4+
namespace Sisk.IniConfiguration.Core;
145

156
/// <summary>
167
/// Represents an INI document.
@@ -25,19 +16,13 @@ public sealed class IniDocument {
2516
/// <summary>
2617
/// Gets all INI sections defined in this INI document.
2718
/// </summary>
28-
public IList<IniSection> Sections { get; }
19+
public IniSectionCollection Sections { get; }
2920

3021
/// <summary>
3122
/// Gets the global INI section, which is the primary section in the document.
3223
/// </summary>
3324
public IniSection Global {
34-
get {
35-
if (this.Sections.Count == 0) {
36-
return new IniSection ( IniReader.INITIAL_SECTION_NAME, Array.Empty<(string, string)> () );
37-
}
38-
else
39-
return this.Sections [ 0 ];
40-
}
25+
get => this.Sections.GetGlobal ();
4126
}
4227

4328
/// <summary>
@@ -89,8 +74,21 @@ public static IniDocument FromStream ( TextReader reader ) {
8974
return parser.Read ();
9075
}
9176

92-
internal IniDocument ( IniSection [] sections ) {
93-
this.Sections = IniSection.MergeIniSections ( sections );
77+
/// <summary>
78+
/// Creates an new <see cref="IniDocument"/> instance from the
79+
/// specified <see cref="IniSection"/> collection.
80+
/// </summary>
81+
/// <param name="sections">The list of <see cref="IniSection"/>.</param>
82+
public IniDocument ( IEnumerable<IniSection> sections ) {
83+
this.Sections = new IniSectionCollection ( sections );
84+
}
85+
86+
/// <summary>
87+
/// Creates an new empty <see cref="IniDocument"/> instance with no
88+
/// INI sections added to it.
89+
/// </summary>
90+
public IniDocument () {
91+
this.Sections = new IniSectionCollection ();
9492
}
9593

9694
/// <summary>
@@ -106,4 +104,15 @@ internal IniDocument ( IniSection [] sections ) {
106104
}
107105
return null;
108106
}
107+
108+
/// <summary>
109+
/// Gets the INI document string from this <see cref="IniDocument"/>.
110+
/// </summary>
111+
public override string ToString () {
112+
using (var sw = new StringWriter ())
113+
using (var iw = new IniWriter ( sw )) {
114+
iw.Write ( this );
115+
return sw.ToString ();
116+
}
117+
}
109118
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
using System.Collections;
2+
using System.Diagnostics.CodeAnalysis;
3+
using Sisk.IniConfiguration.Core.Serialization;
4+
5+
namespace Sisk.IniConfiguration.Core;
6+
7+
/// <summary>
8+
/// Represents an INI section, which contains it's own properties.
9+
/// </summary>
10+
public sealed class IniSection : IDictionary<string, string []> {
11+
internal List<KeyValuePair<string, string>> items;
12+
13+
/// <summary>
14+
/// Gets the INI section name.
15+
/// </summary>
16+
public string Name { get; }
17+
18+
/// <summary>
19+
/// Initializes a new instance of the <see cref="IniSection"/> class with the specified name.
20+
/// </summary>
21+
/// <param name="name">The name of the INI section.</param>
22+
public IniSection ( string name ) {
23+
this.items = new List<KeyValuePair<string, string>> ();
24+
this.Name = name;
25+
}
26+
27+
/// <summary>
28+
/// Initializes a new instance of the <see cref="IniSection"/> class with the specified name and items.
29+
/// </summary>
30+
/// <param name="name">The name of the INI section.</param>
31+
/// <param name="items">A collection of key-value pairs to be added to the section.</param>
32+
public IniSection ( string name, IEnumerable<KeyValuePair<string, string>> items ) {
33+
this.items = items.ToList ();
34+
this.Name = name;
35+
}
36+
37+
/// <summary>
38+
/// Gets all values associated with the specified property name, performing an case-insensitive search.
39+
/// </summary>
40+
/// <param name="key">The property name.</param>
41+
public string [] this [ string key ] {
42+
get {
43+
return this.items
44+
.Where ( k => IniReader.IniNamingComparer.Compare ( key, k.Key ) == 0 )
45+
.Select ( k => k.Value )
46+
.ToArray ();
47+
}
48+
}
49+
50+
/// <summary>
51+
/// Gets all keys defined in this INI section, without duplicates.
52+
/// </summary>
53+
public ICollection<string> Keys {
54+
get {
55+
return this.items.Select ( i => i.Key ).Distinct ().ToArray ();
56+
}
57+
}
58+
59+
/// <summary>
60+
/// Gets all values defined in this INI section.
61+
/// </summary>
62+
public ICollection<string []> Values {
63+
get {
64+
List<string []> values = new List<string []> ( this.Count );
65+
using (var e = this.GetEnumerator ()) {
66+
while (e.MoveNext ()) {
67+
values.Add ( e.Current.Value );
68+
}
69+
}
70+
return values.ToArray ();
71+
}
72+
}
73+
74+
/// <summary>
75+
/// Gets the number of properties in this INI section.
76+
/// </summary>
77+
public int Count => this.items.Count;
78+
79+
/// <inheritdoc/>
80+
public bool IsReadOnly => false;
81+
82+
/// <inheritdoc/>
83+
string [] IDictionary<string, string []>.this [ string key ] {
84+
get => this.GetMany ( key );
85+
set {
86+
this.Remove ( key );
87+
this.Add ( key, value );
88+
}
89+
}
90+
91+
/// <summary>
92+
/// Gets the last value defined in this INI section by their property name.
93+
/// </summary>
94+
/// <param name="key">The property name.</param>
95+
/// <returns>The last value associated with the specified property name, or null if nothing is found.</returns>
96+
public string? GetOne ( string key ) {
97+
return this.items
98+
.Where ( k => IniReader.IniNamingComparer.Compare ( key, k.Key ) == 0 )
99+
.Select ( k => k.Value )
100+
.LastOrDefault ();
101+
}
102+
103+
/// <summary>
104+
/// Gets all values defined in this INI section by their property name.
105+
/// </summary>
106+
/// <param name="key">The property name.</param>
107+
/// <returns>All values associated with the specified property name.</returns>
108+
public string [] GetMany ( string key ) {
109+
return this [ key ];
110+
}
111+
112+
/// <summary>
113+
/// Gets an boolean indicating if the specified key/property name is
114+
/// defined in this <see cref="IniSection"/>.
115+
/// </summary>
116+
/// <param name="key">The property name.</param>
117+
/// <returns>An <see cref="bool"/> indicating if the specified property name is defined or not.</returns>
118+
public bool ContainsKey ( string key ) {
119+
for (int i = 0; i < this.items.Count; i++) {
120+
var item = this.items [ i ];
121+
122+
if (IniReader.IniNamingComparer.Compare ( item.Key, key ) == 0)
123+
return true;
124+
}
125+
return false;
126+
}
127+
128+
/// <inheritdoc/>
129+
public IEnumerator<KeyValuePair<string, string []>> GetEnumerator () {
130+
string [] keysDistinct = this.items.Select ( i => i.Key ).Distinct ().ToArray ();
131+
132+
foreach (string key in keysDistinct) {
133+
string [] valuesByKey = this.items
134+
.Where ( i => i.Key == key )
135+
.Select ( i => i.Value )
136+
.ToArray ();
137+
138+
yield return new KeyValuePair<string, string []> ( key, valuesByKey );
139+
}
140+
}
141+
142+
/// <inheritdoc/>
143+
public bool TryGetValue ( string key, [MaybeNullWhen ( false )] out string [] value ) {
144+
value = this [ key ];
145+
return value.Length > 0;
146+
}
147+
148+
IEnumerator IEnumerable.GetEnumerator () {
149+
return this.GetEnumerator ();
150+
}
151+
152+
/// <inheritdoc/>
153+
public void Add ( string key, string [] value ) {
154+
foreach (var val in value)
155+
this.items.Add ( new KeyValuePair<string, string> ( key, val ) );
156+
}
157+
158+
/// <summary>
159+
/// Adds a new key-value pair to the INI section.
160+
/// </summary>
161+
/// <param name="key">The key to be added.</param>
162+
/// <param name="value">The value associated with the key, or <c>null</c> to set an empty value.</param>
163+
public void Add ( string key, string? value ) {
164+
this.items.Add ( new KeyValuePair<string, string> ( key, value ?? string.Empty ) );
165+
}
166+
167+
/// <inheritdoc/>
168+
public bool Remove ( string key ) {
169+
for (int i = 0; i < this.items.Count; i++) {
170+
var item = this.items [ i ];
171+
172+
if (IniReader.IniNamingComparer.Compare ( item.Key, key ) == 0) {
173+
this.items.RemoveAt ( i );
174+
return true;
175+
}
176+
}
177+
return false;
178+
}
179+
180+
/// <inheritdoc/>
181+
public void Add ( KeyValuePair<string, string []> item ) {
182+
this.Add ( item.Key, item.Value );
183+
}
184+
185+
/// <inheritdoc/>
186+
public void Clear () {
187+
this.items.Clear ();
188+
}
189+
190+
/// <inheritdoc/>
191+
public bool Contains ( KeyValuePair<string, string []> item ) {
192+
for (int i = 0; i < this.items.Count; i++) {
193+
var current = this.items [ i ];
194+
195+
if (IniReader.IniNamingComparer.Compare ( current.Key, item.Key ) == 0 &&
196+
item.Value.Any ( i => i == current.Value ))
197+
return true;
198+
}
199+
return false;
200+
}
201+
202+
/// <summary>
203+
/// This method is not supported and will throw an <see cref="NotSupportedException"/>.
204+
/// </summary>
205+
public void CopyTo ( KeyValuePair<string, string []> [] array, int arrayIndex ) {
206+
throw new NotSupportedException ();
207+
}
208+
209+
/// <inheritdoc/>
210+
public bool Remove ( KeyValuePair<string, string []> item ) {
211+
for (int i = 0; i < this.items.Count; i++) {
212+
var current = this.items [ i ];
213+
214+
if (IniReader.IniNamingComparer.Compare ( current.Key, item.Key ) == 0 &&
215+
item.Value.Any ( i => i == current.Value )) {
216+
this.items.RemoveAt ( i );
217+
return true;
218+
}
219+
}
220+
return false;
221+
}
222+
}

0 commit comments

Comments
 (0)