-
Notifications
You must be signed in to change notification settings - Fork 74
Expand file tree
/
Copy pathUpdateOption.cs
More file actions
240 lines (199 loc) · 8.36 KB
/
Copy pathUpdateOption.cs
File metadata and controls
240 lines (199 loc) · 8.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Text;
using System.Threading;
using GeneralUpdate.Common.Shared.Object.Enum;
namespace GeneralUpdate.Common.Internal.Bootstrap
{
public abstract class UpdateOption : AbstractConstant<UpdateOption>
{
private class UpdateOptionPool : ConstantPool
{
protected override IConstant NewConstant<T>(int id, string name) => new UpdateOption<T>(id, name);
}
private static readonly UpdateOptionPool Pool = new();
public static UpdateOption<T> ValueOf<T>(string name) => (UpdateOption<T>)Pool.ValueOf<T>(name);
/// <summary>
/// Update the file format of the package.
/// </summary>
public static readonly UpdateOption<string> Format = ValueOf<string>("COMPRESSFORMAT");
/// <summary>
/// Compress encoding.
/// </summary>
public static readonly UpdateOption<Encoding> Encoding = ValueOf<Encoding>("COMPRESSENCODING");
/// <summary>
/// Timeout period (unit: second). If this parameter is not specified, the default timeout period is 30 seconds.
/// </summary>
public static readonly UpdateOption<int?> DownloadTimeOut = ValueOf<int?>("DOWNLOADTIMEOUT");
/// <summary>
/// Whether to enable the driver upgrade function.
/// </summary>
public static readonly UpdateOption<bool?> Drive = ValueOf<bool?>("DRIVE");
/// <summary>
/// Whether to enable the patch function.
/// </summary>
public static readonly UpdateOption<bool?> Patch = ValueOf<bool?>("PATCH");
/// <summary>
/// Whether to enable the backup function.
/// </summary>
public static readonly UpdateOption<bool?> BackUp = ValueOf<bool?>("BACKUP");
/// <summary>
/// Specifies the update execution mode.
/// </summary>
public static readonly UpdateOption<UpdateMode?> Mode = ValueOf<UpdateMode?>("MODE");
/// <summary>
/// Whether to enable silent update mode.
/// </summary>
public static readonly UpdateOption<bool> EnableSilentUpdate = ValueOf<bool>("ENABLESILENTUPDATE");
internal UpdateOption(int id, string name)
: base(id, name) { }
public abstract bool Set(IUpdateConfiguration configuration, object value);
}
public sealed class UpdateOption<T> : UpdateOption
{
internal UpdateOption(int id, string name)
: base(id, name)
{
}
public void Validate(T value) => Contract.Requires(value != null);
public override bool Set(IUpdateConfiguration configuration, object value) => configuration.SetOption(this, (T)value);
}
public abstract class ConstantPool
{
private readonly Dictionary<string, IConstant> constants = new Dictionary<string, IConstant>();
private int nextId = 1;
/// <summary>Shortcut of <c>this.ValueOf(firstNameComponent.Name + "#" + secondNameComponent)</c>.</summary>
public IConstant ValueOf<T>(Type firstNameComponent, string secondNameComponent)
{
Contract.Requires(firstNameComponent != null);
Contract.Requires(secondNameComponent != null);
return this.ValueOf<T>(firstNameComponent.Name + '#' + secondNameComponent);
}
/// <summary>
/// Returns the <see cref="IConstant" /> which is assigned to the specified <c>name</c>.
/// If there's no such <see cref="IConstant" />, a new one will be created and returned.
/// Once created, the subsequent calls with the same <c>name</c> will always return the previously created one
/// (i.e. singleton.)
/// </summary>
/// <param name="name">the name of the <see cref="IConstant" /></param>
public IConstant ValueOf<T>(string name)
{
IConstant constant;
lock (this.constants)
{
if (this.constants.TryGetValue(name, out constant))
{
return constant;
}
else
{
constant = this.NewInstance0<T>(name);
}
}
return constant;
}
/// <summary>Returns <c>true</c> if a <see cref="AttributeKey{T}" /> exists for the given <c>name</c>.</summary>
public bool Exists(string name)
{
CheckNotNullAndNotEmpty(name);
lock (this.constants)
return this.constants.ContainsKey(name);
}
/// <summary>
/// Creates a new <see cref="IConstant" /> for the given <c>name</c> or fail with an
/// <see cref="ArgumentException" /> if a <see cref="IConstant" /> for the given <c>name</c> exists.
/// </summary>
public IConstant NewInstance<T>(string name)
{
if (this.Exists(name)) throw new ArgumentException($"'{name}' is already in use");
IConstant constant = this.NewInstance0<T>(name);
return constant;
}
// Be careful that this dose not check whether the argument is null or empty.
private IConstant NewInstance0<T>(string name)
{
lock (this.constants)
{
IConstant constant = this.NewConstant<T>(this.nextId, name);
this.constants[name] = constant;
this.nextId++;
return constant;
}
}
private static void CheckNotNullAndNotEmpty(string name) => Contract.Requires(!string.IsNullOrEmpty(name));
protected abstract IConstant NewConstant<T>(int id, string name);
[Obsolete]
public int NextId()
{
lock (this.constants)
{
int id = this.nextId;
this.nextId++;
return id;
}
}
}
public interface IConstant
{
/// <summary>Returns the unique number assigned to this <see cref="IConstant" />.</summary>
int Id { get; }
/// <summary>Returns the name of this <see cref="IConstant" />.</summary>
string Name { get; }
}
public interface IUpdateConfiguration
{
T GetOption<T>(UpdateOption<T> option);
bool SetOption(UpdateOption option, object value);
bool SetOption<T>(UpdateOption<T> option, T value);
}
public abstract class AbstractConstant : IConstant
{
private static long nextUniquifier;
private long volatileUniquifier;
protected AbstractConstant(int id, string name)
{
this.Id = id;
this.Name = name;
}
public int Id { get; }
public string Name { get; }
public override sealed string ToString() => this.Name;
protected long Uniquifier
{
get
{
long result;
if ((result = Volatile.Read(ref this.volatileUniquifier)) == 0)
{
result = Interlocked.Increment(ref nextUniquifier);
long previousUniquifier = Interlocked.CompareExchange(ref this.volatileUniquifier, result, 0);
if (previousUniquifier != 0) result = previousUniquifier;
}
return result;
}
}
}
public abstract class AbstractConstant<T> : AbstractConstant, IComparable<T>, IEquatable<T>
where T : AbstractConstant<T>
{
/// <summary>Creates a new instance.</summary>
protected AbstractConstant(int id, string name)
: base(id, name) { }
public override sealed int GetHashCode() => base.GetHashCode();
public override sealed bool Equals(object obj) => base.Equals(obj);
public bool Equals(T other) => ReferenceEquals(this, other);
public int CompareTo(T o)
{
if (ReferenceEquals(this, o)) return 0;
AbstractConstant<T> other = o;
int returnCode = this.GetHashCode() - other.GetHashCode();
if (returnCode != 0) return returnCode;
long thisUV = this.Uniquifier;
long otherUV = other.Uniquifier;
if (thisUV < otherUV) return -1;
if (thisUV > otherUV) return 1;
throw new System.Exception("failed to compare two different constants");
}
}
}