Welcome to mirror list, hosted at ThFree Co, Russian Federation.

MockEnumPropertyInfo.cs « MockPropertyInfo « Xamarin.PropertyEditing.Tests - github.com/xamarin/Xamarin.PropertyEditing.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: fd4be861ddae5ef45dcbb1529a807b3af3e67401 (plain)
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
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Xamarin.PropertyEditing.Tests.MockControls;

namespace Xamarin.PropertyEditing.Tests.MockPropertyInfo
{
	/// <summary>
	/// Information about an enum or flag type property.
	/// </summary>
	/// <typeparam name="TUnderlying">The underlying type for the enum or flag.</typeparam>
	public class MockEnumPropertyInfo<TUnderlying, TEnum>
		: MockPropertyInfo<TEnum>, IHavePredefinedValues<TUnderlying>
		where TUnderlying : struct
		where TEnum : struct
	{
		public MockEnumPropertyInfo (string name, string description = null, string category = "", bool canWrite = true, bool flag = false, IEnumerable<Type> converterTypes = null, bool constrained = true)
			: base (name, description, category, canWrite, converterTypes)
		{
			var names = Enum.GetNames (typeof (TEnum));
			Values = Enum.GetValues (typeof (TEnum)).Cast<TUnderlying>().ToArray();

			LongValues = new ulong[names.Length];

			unchecked {
				var predefinedValues = new Dictionary<string, TUnderlying> (names.Length);
				for (var i = 0; i < names.Length; i++) {
					predefinedValues.Add (names[i], Values[i]);
					LongValues[i] = Convert.ToUInt64 (Values[i]);
				}

				PredefinedValues = predefinedValues;
			}

			IsConstrainedToPredefined = constrained;
			IsValueCombinable = flag;
		}

		public override Type Type => typeof (TEnum);

		public bool IsConstrainedToPredefined { get; }

		public bool IsValueCombinable { get; }

		public IReadOnlyDictionary<string, TUnderlying> PredefinedValues { get; }

		public override bool TryConvert<TFrom> (TFrom fromValue, Type toType, out object toValue)
		{
			var enumerationType = toType
				.GetInterfaces ()
				.FirstOrDefault (i => i.IsGenericType && i.GetGenericTypeDefinition () == typeof (IEnumerable<>));
			if (enumerationType != null) {
				// We're being asked for a list of values.
				var enumeratedType = enumerationType.GetGenericArguments ()[0];
				var listOfEnumeratedType = typeof (List<>).MakeGenericType (enumeratedType);
				// Build the list of values through a trip to uint64
				unchecked {
					var realValue = Convert.ToUInt64 (fromValue);
					var values = (IList)Activator.CreateInstance (listOfEnumeratedType);
					for (var i = 0; i < Values.Length; i++) {
						if ((LongValues[i] & realValue) != 0)
							values.Add (Convert.ChangeType(Values[i], enumeratedType));
					}

					toValue = values;
					return true;
				}
			} else if (fromValue is IEnumerable) {
				if (!IsValueCombinable)
					throw new ArgumentException ("Can't set a combined value on a non-combinable type", nameof(TFrom));

				unchecked {
					var realValue = Convert.ToUInt64 (default(TUnderlying));
					foreach (var val in (IEnumerable) fromValue) {
						realValue |= Convert.ToUInt64 (val);
					}

					if (toType.IsEnum)
						toValue = Enum.ToObject (toType, realValue);
					else
						toValue = realValue;
					return true;
				}
			} else if (toType.IsEnum) {
				toValue = Enum.ToObject (toType, fromValue);
				return true;
			}

			return base.TryConvert (fromValue, toType, out toValue);
		}

		private TUnderlying[] Values;
		private ulong[] LongValues;
	}
}