Skip to content

Commit 5c6f6b6

Browse files
committed
Register also various Collection interfaces.
1 parent 269c86f commit 5c6f6b6

4 files changed

+308
-17
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
//HintName: CollectionRegistrations.g.cs
2+
// <auto-generated/>
3+
#nullable enable
4+
using System;
5+
using System.Runtime.CompilerServices;
6+
[CompilerGenerated]
7+
static file class CollectionRegistrations
8+
{
9+
[ModuleInitializer]
10+
internal static void Register4BTDB()
11+
{
12+
BTDB.Serialization.ReflectionMetadata.RegisterCollection(new()
13+
{
14+
Type = typeof(global::System.Collections.Generic.IList<string>),
15+
ElementKeyType = typeof(string),
16+
Creator = &Create1,
17+
Adder = &Add1
18+
});
19+
20+
static object Create1(uint capacity)
21+
{
22+
return new global::System.Collections.Generic.List<string>((int)capacity);
23+
}
24+
25+
static void Add1(object c, ref byte value)
26+
{
27+
Unsafe.As<global::System.Collections.Generic.List<string>>(c).Add(Unsafe.As<byte, string>(ref value));
28+
}
29+
30+
BTDB.Serialization.ReflectionMetadata.RegisterCollection(new()
31+
{
32+
Type = typeof(global::System.Collections.Generic.IDictionary<int, global::System.Collections.Generic.IList<string>>),
33+
ElementKeyType = typeof(int),
34+
ElementValueType = typeof(global::System.Collections.Generic.IList<string>),
35+
Creator = &Create2,
36+
AdderKeyValue = &Add2
37+
});
38+
39+
static object Create2(uint capacity)
40+
{
41+
return new global::System.Collections.Generic.Dictionary<int, global::System.Collections.Generic.IList<string>>((int)capacity);
42+
}
43+
44+
static void Add2(object c, ref byte key, ref byte value)
45+
{
46+
Unsafe.As<global::System.Collections.Generic.Dictionary<int, global::System.Collections.Generic.IList<string>>>(c).Add(Unsafe.As<byte, int>(ref key), Unsafe.As<byte, global::System.Collections.Generic.IList<string>>(ref value));
47+
}
48+
49+
BTDB.Serialization.ReflectionMetadata.RegisterCollection(new()
50+
{
51+
Type = typeof(global::System.Collections.Generic.IReadOnlyList<string>),
52+
ElementKeyType = typeof(string),
53+
Creator = &Create3,
54+
Adder = &Add3
55+
});
56+
57+
static object Create3(uint capacity)
58+
{
59+
return new global::System.Collections.Generic.List<string>((int)capacity);
60+
}
61+
62+
static void Add3(object c, ref byte value)
63+
{
64+
Unsafe.As<global::System.Collections.Generic.List<string>>(c).Add(Unsafe.As<byte, string>(ref value));
65+
}
66+
67+
BTDB.Serialization.ReflectionMetadata.RegisterCollection(new()
68+
{
69+
Type = typeof(global::System.Collections.Generic.IReadOnlyDictionary<int, global::System.Collections.Generic.IReadOnlyList<string>>),
70+
ElementKeyType = typeof(int),
71+
ElementValueType = typeof(global::System.Collections.Generic.IReadOnlyList<string>),
72+
Creator = &Create4,
73+
AdderKeyValue = &Add4
74+
});
75+
76+
static object Create4(uint capacity)
77+
{
78+
return new global::System.Collections.Generic.Dictionary<int, global::System.Collections.Generic.IReadOnlyList<string>>((int)capacity);
79+
}
80+
81+
static void Add4(object c, ref byte key, ref byte value)
82+
{
83+
Unsafe.As<global::System.Collections.Generic.Dictionary<int, global::System.Collections.Generic.IReadOnlyList<string>>>(c).Add(Unsafe.As<byte, int>(ref key), Unsafe.As<byte, global::System.Collections.Generic.IReadOnlyList<string>>(ref value));
84+
}
85+
86+
BTDB.Serialization.ReflectionMetadata.RegisterCollection(new()
87+
{
88+
Type = typeof(global::System.Collections.Generic.IEnumerable<string>),
89+
ElementKeyType = typeof(string),
90+
Creator = &Create5,
91+
Adder = &Add5
92+
});
93+
94+
static object Create5(uint capacity)
95+
{
96+
return new global::System.Collections.Generic.List<string>((int)capacity);
97+
}
98+
99+
static void Add5(object c, ref byte value)
100+
{
101+
Unsafe.As<global::System.Collections.Generic.List<string>>(c).Add(Unsafe.As<byte, string>(ref value));
102+
}
103+
104+
BTDB.Serialization.ReflectionMetadata.RegisterCollection(new()
105+
{
106+
Type = typeof(global::System.Collections.Generic.ISet<string>),
107+
ElementKeyType = typeof(string),
108+
Creator = &Create6,
109+
Adder = &Add6
110+
});
111+
112+
static object Create6(uint capacity)
113+
{
114+
return new global::System.Collections.Generic.HashSet<string>((int)capacity);
115+
}
116+
117+
static void Add6(object c, ref byte value)
118+
{
119+
Unsafe.As<global::System.Collections.Generic.HashSet<string>>(c).Add(Unsafe.As<byte, string>(ref value));
120+
}
121+
122+
BTDB.Serialization.ReflectionMetadata.RegisterCollection(new()
123+
{
124+
Type = typeof(global::System.Collections.Generic.IReadOnlySet<string>),
125+
ElementKeyType = typeof(string),
126+
Creator = &Create7,
127+
Adder = &Add7
128+
});
129+
130+
static object Create7(uint capacity)
131+
{
132+
return new global::System.Collections.Generic.HashSet<string>((int)capacity);
133+
}
134+
135+
static void Add7(object c, ref byte value)
136+
{
137+
Unsafe.As<global::System.Collections.Generic.HashSet<string>>(c).Add(Unsafe.As<byte, string>(ref value));
138+
}
139+
}
140+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//HintName: TestNamespace.Person.g.cs
2+
// <auto-generated/>
3+
#pragma warning disable 612,618
4+
using System;
5+
using System.Runtime.CompilerServices;
6+
7+
namespace TestNamespace;
8+
9+
[CompilerGenerated]
10+
static file class PersonRegistration
11+
{
12+
[UnsafeAccessor(UnsafeAccessorKind.Constructor)]
13+
extern static global::TestNamespace.Person Creator();
14+
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "<Name>k__BackingField")]
15+
extern static ref string Field1(global::TestNamespace.Person @this);
16+
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "<Id2Names>k__BackingField")]
17+
extern static ref global::System.Collections.Generic.IDictionary<int, global::System.Collections.Generic.IList<string>> Field2(global::TestNamespace.Person @this);
18+
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "<Id2Names2>k__BackingField")]
19+
extern static ref global::System.Collections.Generic.IReadOnlyDictionary<int, global::System.Collections.Generic.IReadOnlyList<string>> Field3(global::TestNamespace.Person @this);
20+
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "<Names>k__BackingField")]
21+
extern static ref global::System.Collections.Generic.IEnumerable<string> Field4(global::TestNamespace.Person @this);
22+
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "<NameSet>k__BackingField")]
23+
extern static ref global::System.Collections.Generic.ISet<string> Field5(global::TestNamespace.Person @this);
24+
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "<NameSet2>k__BackingField")]
25+
extern static ref global::System.Collections.Generic.IReadOnlySet<string> Field6(global::TestNamespace.Person @this);
26+
[ModuleInitializer]
27+
internal static unsafe void Register4BTDB()
28+
{
29+
global::BTDB.IOC.IContainer.RegisterFactory(typeof(global::TestNamespace.Person), (container, ctx) =>
30+
{
31+
return (container2, ctx2) =>
32+
{
33+
var res = new global::TestNamespace.Person();
34+
return res;
35+
};
36+
});
37+
var metadata = new global::BTDB.Serialization.ClassMetadata();
38+
metadata.Name = "Person";
39+
metadata.Type = typeof(global::TestNamespace.Person);
40+
metadata.Namespace = "TestNamespace";
41+
metadata.Implements = [];
42+
metadata.Creator = &Creator;
43+
var dummy = Unsafe.As<global::TestNamespace.Person>(metadata);
44+
metadata.Fields = new[]
45+
{
46+
new global::BTDB.Serialization.FieldMetadata
47+
{
48+
Name = "Name",
49+
Type = typeof(string),
50+
ByteOffset = global::BTDB.Serialization.RawData.CalcOffset(dummy, ref Field1(dummy)),
51+
},
52+
new global::BTDB.Serialization.FieldMetadata
53+
{
54+
Name = "Id2Names",
55+
Type = typeof(global::System.Collections.Generic.IDictionary<int, global::System.Collections.Generic.IList<string>>),
56+
ByteOffset = global::BTDB.Serialization.RawData.CalcOffset(dummy, ref Field2(dummy)),
57+
},
58+
new global::BTDB.Serialization.FieldMetadata
59+
{
60+
Name = "Id2Names2",
61+
Type = typeof(global::System.Collections.Generic.IReadOnlyDictionary<int, global::System.Collections.Generic.IReadOnlyList<string>>),
62+
ByteOffset = global::BTDB.Serialization.RawData.CalcOffset(dummy, ref Field3(dummy)),
63+
},
64+
new global::BTDB.Serialization.FieldMetadata
65+
{
66+
Name = "Names",
67+
Type = typeof(global::System.Collections.Generic.IEnumerable<string>),
68+
ByteOffset = global::BTDB.Serialization.RawData.CalcOffset(dummy, ref Field4(dummy)),
69+
},
70+
new global::BTDB.Serialization.FieldMetadata
71+
{
72+
Name = "NameSet",
73+
Type = typeof(global::System.Collections.Generic.ISet<string>),
74+
ByteOffset = global::BTDB.Serialization.RawData.CalcOffset(dummy, ref Field5(dummy)),
75+
},
76+
new global::BTDB.Serialization.FieldMetadata
77+
{
78+
Name = "NameSet2",
79+
Type = typeof(global::System.Collections.Generic.IReadOnlySet<string>),
80+
ByteOffset = global::BTDB.Serialization.RawData.CalcOffset(dummy, ref Field6(dummy)),
81+
},
82+
};
83+
global::BTDB.Serialization.ReflectionMetadata.Register(metadata);
84+
}
85+
}

BTDB.SourceGenerator.Test/MetadataTests.cs

+21
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,27 @@ public class Person
7575
""");
7676
}
7777

78+
[Fact]
79+
public Task VerifyMoreCollections()
80+
{
81+
// language=cs
82+
return VerifySourceGenerator("""
83+
using System.Collections.Generic;
84+
namespace TestNamespace;
85+
86+
[BTDB.Generate]
87+
public class Person
88+
{
89+
public string Name { get; set; } = "";
90+
public IDictionary<int,IList<string>> Id2Names { get; set; }
91+
public IReadOnlyDictionary<int,IReadOnlyList<string>> Id2Names2 { get; set; }
92+
public IEnumerable<string> Names { get; set; }
93+
public ISet<string> NameSet { get; set; }
94+
public IReadOnlySet<string> NameSet2 { get; set; }
95+
}
96+
""");
97+
}
98+
7899
[Fact]
79100
public Task VerifyImplementsInterface()
80101
{

BTDB.SourceGenerator/Main.cs

+62-17
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,7 @@ void GatherCollections(SemanticModel model, IEnumerable<ITypeSymbol> types, Hash
450450

451451
void GatherCollection(SemanticModel model, ITypeSymbol type, HashSet<CollectionInfo> collections)
452452
{
453-
if (type.TypeKind != TypeKind.Class) return;
453+
if (type.TypeKind != TypeKind.Class && type.TypeKind != TypeKind.Interface) return;
454454
if (type is INamedTypeSymbol namedTypeSymbol)
455455
{
456456
if (namedTypeSymbol.IsGenericType)
@@ -462,24 +462,63 @@ void GatherCollection(SemanticModel model, ITypeSymbol type, HashSet<CollectionI
462462
}
463463

464464
var fullName = namedTypeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
465-
if (fullName.StartsWith("global::System.Collections.Generic.HashSet<")
466-
|| fullName.StartsWith("global::System.Collections.Generic.List<"))
465+
ReadOnlySpan<string> collectionToInstance =
466+
[
467+
"global::System.Collections.Generic.List<", "global::System.Collections.Generic.List<",
468+
"global::System.Collections.Generic.IList<", "global::System.Collections.Generic.List<",
469+
"global::System.Collections.Generic.IReadOnlyList<", "global::System.Collections.Generic.List<",
470+
"global::System.Collections.Generic.HashSet<", "global::System.Collections.Generic.HashSet<",
471+
"global::System.Collections.Generic.ISet<", "global::System.Collections.Generic.HashSet<",
472+
"global::System.Collections.Generic.IReadOnlySet<", "global::System.Collections.Generic.HashSet<",
473+
"global::System.Collections.Generic.IEnumerable<", "global::System.Collections.Generic.List<",
474+
];
475+
string? instance = null;
476+
for (var i = 0; i < collectionToInstance.Length; i += 2)
477+
{
478+
if (fullName.StartsWith(collectionToInstance[i], StringComparison.Ordinal))
479+
{
480+
instance = collectionToInstance[i + 1] + fullName.Substring(collectionToInstance[i].Length);
481+
break;
482+
}
483+
}
484+
485+
if (instance != null)
467486
{
468487
var elementType = namedTypeSymbol.TypeArguments[0];
469-
var collectionInfo = new CollectionInfo(fullName,
488+
var collectionInfo = new CollectionInfo(fullName, instance,
470489
elementType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
471490
elementType.IsReferenceType, null, null);
472491
collections.Add(collectionInfo);
473492
}
474-
else if (fullName.StartsWith("global::System.Collections.Generic.Dictionary<"))
493+
else
475494
{
476-
var keyType = namedTypeSymbol.TypeArguments[0];
477-
var valueType = namedTypeSymbol.TypeArguments[1];
478-
var collectionInfo = new CollectionInfo(fullName,
479-
keyType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
480-
keyType.IsReferenceType, valueType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
481-
valueType.IsReferenceType);
482-
collections.Add(collectionInfo);
495+
ReadOnlySpan<string> collectionToInstance2 =
496+
[
497+
"global::System.Collections.Generic.Dictionary<", "global::System.Collections.Generic.Dictionary<",
498+
"global::System.Collections.Generic.IDictionary<", "global::System.Collections.Generic.Dictionary<",
499+
"global::System.Collections.Generic.IReadOnlyDictionary<",
500+
"global::System.Collections.Generic.Dictionary<",
501+
];
502+
instance = null;
503+
for (var i = 0; i < collectionToInstance2.Length; i += 2)
504+
{
505+
if (fullName.StartsWith(collectionToInstance2[i], StringComparison.Ordinal))
506+
{
507+
instance = collectionToInstance2[i + 1] + fullName.Substring(collectionToInstance2[i].Length);
508+
break;
509+
}
510+
}
511+
512+
if (instance != null)
513+
{
514+
var keyType = namedTypeSymbol.TypeArguments[0];
515+
var valueType = namedTypeSymbol.TypeArguments[1];
516+
var collectionInfo = new CollectionInfo(fullName, instance,
517+
keyType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
518+
keyType.IsReferenceType, valueType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
519+
valueType.IsReferenceType);
520+
collections.Add(collectionInfo);
521+
}
483522
}
484523
}
485524
}
@@ -667,12 +706,12 @@ internal static void Register4BTDB()
667706
668707
static object Create{{idx}}(uint capacity)
669708
{
670-
return new {{collection.FullName}}((int)capacity);
709+
return new {{collection.InstantiableFullName}}((int)capacity);
671710
}
672711
673712
static void Add{{idx}}(object c, ref byte key, ref byte value)
674713
{
675-
Unsafe.As<{{collection.FullName}}>(c).Add(Unsafe.As<byte, {{collection.KeyType}}>(ref key), Unsafe.As<byte, {{collection.ValueType}}>(ref value));
714+
Unsafe.As<{{collection.InstantiableFullName}}>(c).Add(Unsafe.As<byte, {{collection.KeyType}}>(ref key), Unsafe.As<byte, {{collection.ValueType}}>(ref value));
676715
}
677716
678717
""");
@@ -692,12 +731,12 @@ internal static void Register4BTDB()
692731
693732
static object Create{{idx}}(uint capacity)
694733
{
695-
return new {{collection.FullName}}((int)capacity);
734+
return new {{collection.InstantiableFullName}}((int)capacity);
696735
}
697736
698737
static void Add{{idx}}(object c, ref byte value)
699738
{
700-
Unsafe.As<{{collection.FullName}}>(c).Add(Unsafe.As<byte, {{collection.KeyType}}>(ref value));
739+
Unsafe.As<{{collection.InstantiableFullName}}>(c).Add(Unsafe.As<byte, {{collection.KeyType}}>(ref value));
701740
}
702741
703742
""");
@@ -1192,7 +1231,13 @@ record GenerationInfo(
11921231
Location? Location
11931232
);
11941233

1195-
record CollectionInfo(string FullName, string KeyType, bool KeyIsReference, string? ValueType, bool? ValueIsReference);
1234+
record CollectionInfo(
1235+
string FullName,
1236+
string InstantiableFullName,
1237+
string KeyType,
1238+
bool KeyIsReference,
1239+
string? ValueType,
1240+
bool? ValueIsReference);
11961241

11971242
record ParameterInfo(string Name, string Type, bool IsReference, bool Optional, string? DefaultValue);
11981243

0 commit comments

Comments
 (0)