##// END OF EJS Templates
Closed
Pull request !2 Created on Tue, 02 Feb 2021 11:50:08, by
  • Fixed Safe.DisposeCollection NullReferenceException
  • sync
  • Добавлена метка v3.0.14 для набора изменений 95896f882995
  • Added tests for Implab.ServiceHost.Unity configuration loader.
  • Added IObservable to TraceRegistry
Pull request versions not available.
ver Time Author Commit Description
91 commits hidden, click expand to show them.

The requested changes are too big and content was truncated. Show full diff

@@ -0,0 +1,18
1 {
2 "version": "0.2.0",
3 "configurations": [
4 {
5 "name": ".NET Core Launch (console)",
6 "type": "coreclr",
7 "request": "launch",
8 "preLaunchTask": "build",
9 "program": "${workspaceRoot}/Implab.Playground/bin/Debug/netcoreapp2.0/Implab.Playground.dll",
10 "args": [
11 "-f", "netcoreapp2.0"
12 ],
13 "cwd": "${workspaceRoot}/Implab.Playground",
14 "stopAtEntry": false,
15 "console": "internalConsole"
16 }
17 ]
18 } No newline at end of file
@@ -0,0 +1,12
1 // Поместите параметры в этот файл, чтобы перезаписать параметры по умолчанию и пользовательские параметры.
2 {
3 "files.exclude": {
4 "**/.git": true,
5 "**/.svn": true,
6 "**/.hg": true,
7 "**/CVS": true,
8 "**/.DS_Store": true,
9 "**/bin": true,
10 "**/obj": true
11 }
12 } No newline at end of file
@@ -0,0 +1,37
1 {
2 // See https://go.microsoft.com/fwlink/?LinkId=733558
3 // for the documentation about the tasks.json format
4 "version": "0.1.0",
5 "command": "dotnet",
6 "args": [
7 ],
8 "showOutput": "silent",
9 "tasks": [
10 {
11 "taskName": "build",
12 // Show the output window only if unrecognized errors occur.
13 "showOutput": "always",
14 // Use the standard MS compiler pattern to detect errors, warnings and infos
15 "problemMatcher": "$msCompile",
16
17 "args" : [
18 "/p:Configuration=Debug"
19 ]
20 },
21 {
22 "taskName": "clean",
23 // Show the output window only if unrecognized errors occur.
24 "showOutput": "always",
25 // Use the standard MS compiler pattern to detect errors, warnings and infos
26 "problemMatcher": "$msCompile"
27 },
28 {
29 "taskName": "test",
30 "isTestCommand": true,
31 // Show the output window only if unrecognized errors occur.
32 "showOutput": "always",
33 // Use the standard MS compiler pattern to detect errors, warnings and infos
34 "problemMatcher": "$msCompile"
35 }
36 ]
37 } No newline at end of file
@@ -0,0 +1,6
1 <?xml version="1.0" encoding="utf-8"?>
2 <configuration>
3 <startup>
4 <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/>
5 </startup>
6 </configuration>
@@ -0,0 +1,27
1 <Project Sdk="Microsoft.NET.Sdk">
2 <PropertyGroup Condition="'$(OSTYPE)'=='linux'">
3 <TargetFrameworks>netcoreapp2.0;;net46</TargetFrameworks>
4 <FrameworkPathOverride Condition="'$(TargetFramework)'=='net46'">/usr/lib/mono/4.6-api/</FrameworkPathOverride>
5 </PropertyGroup>
6
7 <PropertyGroup Condition="'$(OSTYPE)'=='windows'">
8 <TargetFrameworks>netcoreapp2.0;net46</TargetFrameworks>
9 </PropertyGroup>
10
11 <PropertyGroup>
12 <OutputType>Exe</OutputType>
13 <IsPackable>false</IsPackable>
14 </PropertyGroup>
15
16 <ItemGroup>
17 <ProjectReference Include="../Implab/Implab.csproj" />
18 <ProjectReference Include="..\Implab.ServiceHost\Implab.ServiceHost.csproj" />
19 </ItemGroup>
20
21 <ItemGroup>
22 <PackageReference Include="Unity" Version="5.8.6" />
23 <PackageReference Include="System.Reactive" Version="4.0.0" />
24
25 </ItemGroup>
26
27 </Project>
@@ -0,0 +1,42
1 using System;
2 using System.Collections.Generic;
3 using System.Diagnostics;
4 using System.Dynamic;
5 using System.Linq;
6 using Implab.Components;
7 using Implab.Diagnostics;
8 using Implab.ServiceHost.Unity;
9 using Implab.Xml;
10 using Unity;
11 using Unity.Injection;
12 using Unity.Registration;
13
14 namespace Implab.Playground {
15 using System.Reactive.Linq;
16 using static Trace<Bar>;
17
18 class Foo {
19
20 }
21
22 class Bar : Foo {
23
24 }
25 public class Program {
26
27 static void Main(string[] args) {
28 Trace<Foo>.Log("First!");
29 Log("+1!");
30
31 using(TraceRegistry.Global.OfType<TraceSourceChannel>().Subscribe(ch => {
32 Console.WriteLine($"{ch.Id}: {ch.Source.Name}");
33
34 })) {
35 Trace<Foo>.Log("Hi!");
36 Log("Respect!");
37 }
38 }
39
40
41 }
42 }
@@ -0,0 +1,74
1 <?xml version="1.0" encoding="UTF-8"?>
2 <container xmlns="http://implab.org/schemas/servicehost/unity.v1.xsd">
3 <namespace name="System"/>
4 <namespace name="System.Collections.Generic"/>
5 <namespace name="Implab.Components"/>
6 <namespace name="Implab.Playground"/>
7
8 <!-- foo1 -->
9 <register name="foo1" type="Foo">
10 <property name="Name">
11 <value>FOO!</value>
12 </property>
13 </register>
14
15 <!-- foo2 -->
16 <register name="foo2" type="Foo">
17 <property name="Name">
18 <value>GOOD</value>
19 </property>
20 <property name="IntValue">
21 <value>2</value>
22 </property>
23 </register>
24
25 <register type="Foo">
26 <method name="AddRange">
27 <array itemsType="Foo">
28 <dependency name="foo2"/>
29 </array>
30 </method>
31 </register>
32
33 <register type="IContainer{}" mapTo="Container{}">
34 <constructor/>
35 <method name="SetInstance">
36 <dependency type="T"/>
37 </method>
38 <method name="AddRange">
39 <array itemsType="T">
40 <dependency name="foo2-bar"/>
41 </array>
42 </method>
43 </register>
44
45 <register type="List{}">
46 <constructor />
47 </register>
48
49 <register type="IContainer{String}" mapTo="Container{String}">
50 <constructor/>
51 <method name="SetInstance">
52 <dependency type="String" name="name1"/>
53 </method>
54 </register>
55
56 <serialized type="Foo+Bar">
57 <Bar xmlns="" id="1">
58 <Name>Baaar</Name>
59 </Bar>
60 </serialized>
61
62 <value name="connection1" type="String"><![CDATA[Connect me <here>!]]></value>
63 <value name="name1" type="String" value="Hello!"/>
64
65 <factory name="foo3" type="IFactory{Foo}" mapTo="FooFactory">
66 <property name="Connection">
67 <value><![CDATA[Wired "" objecty <> name @#$%^&]]></value>
68 </property>
69 <property name="UseSsl">
70 <value>false</value>
71 </property>
72 </factory>
73
74 </container> No newline at end of file
@@ -0,0 +1,29
1 <Project Sdk="Microsoft.NET.Sdk">
2 <PropertyGroup Condition="'$(OSTYPE)'=='linux'">
3 <TargetFrameworks>netcoreapp2.0;net46</TargetFrameworks>
4 <FrameworkPathOverride Condition="'$(TargetFramework)'=='net46'">/usr/lib/mono/4.5/</FrameworkPathOverride>
5 </PropertyGroup>
6
7 <PropertyGroup Condition="'$(OSTYPE)'=='windows'">
8 <TargetFrameworks>netcoreapp2.0;net46</TargetFrameworks>
9 </PropertyGroup>
10
11 <PropertyGroup>
12 <IsPackable>false</IsPackable>
13 </PropertyGroup>
14
15 <ItemGroup>
16 <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.6.0-preview-20180109-01" />
17 <PackageReference Include="System.Reactive" Version="4.0.0" />
18 <PackageReference Include="xunit" Version="2.3.1" />
19 <PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
20 <ProjectReference Include="../Implab/Implab.csproj"/>
21 <ProjectReference Include="../Implab.ServiceHost/Implab.ServiceHost.csproj"/>
22 <DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
23 </ItemGroup>
24
25 <ItemGroup>
26 <None Include="data/**/*.*" CopyToOutputDirectory="PreserveNewest" />
27 </ItemGroup>
28
29 </Project>
@@ -0,0 +1,74
1 <?xml version="1.0" encoding="UTF-8"?>
2 <container xmlns="http://implab.org/schemas/servicehost/unity.v1.xsd">
3 <namespace name="System"/>
4 <namespace name="System.Collections.Generic"/>
5 <namespace name="Implab.Components"/>
6 <namespace name="Implab.ServiceHost.Test.Mock"/>
7
8 <!-- Default FooService -->
9 <register type="FooService{}">
10 <property name="Name">
11 <value>I'm default!</value>
12 </property>
13 </register>
14
15 <!-- foo2 -->
16 <register name="foo2" type="Foo">
17 <property name="Name">
18 <value>GOOD</value>
19 </property>
20 <property name="IntValue">
21 <value>2</value>
22 </property>
23 </register>
24
25 <register type="Foo">
26 <method name="AddRange">
27 <array itemsType="Foo">
28 <dependency name="foo2"/>
29 </array>
30 </method>
31 </register>
32
33 <register type="IContainer{}" mapTo="Container{}">
34 <constructor/>
35 <method name="SetInstance">
36 <dependency type="T"/>
37 </method>
38 <method name="AddRange">
39 <array itemsType="T">
40 <dependency name="foo2-bar"/>
41 </array>
42 </method>
43 </register>
44
45 <register type="List{}">
46 <constructor />
47 </register>
48
49 <register type="IContainer{String}" mapTo="Container{String}">
50 <constructor/>
51 <method name="SetInstance">
52 <dependency type="String" name="name1"/>
53 </method>
54 </register>
55
56 <serialized type="Foo+Bar">
57 <Bar xmlns="" id="1">
58 <Name>Baaar</Name>
59 </Bar>
60 </serialized>
61
62 <value name="connection1" type="String"><![CDATA[Connect me <here>!]]></value>
63 <value name="name1" type="String" value="Hello!"/>
64
65 <factory name="foo3" type="IFactory{Foo}" mapTo="FooFactory">
66 <property name="Connection">
67 <value><![CDATA[Wired "" objecty <> name @#$%^&]]></value>
68 </property>
69 <property name="UseSsl">
70 <value>false</value>
71 </property>
72 </factory>
73
74 </container> No newline at end of file
@@ -0,0 +1,2
1 <container xmlns="http://implab.org/schemas/servicehost/unity.v1.xsd">
2 </container> No newline at end of file
@@ -0,0 +1,65
1 <?xml version="1.0"?>
2 <container xmlns="http://implab.org/schemas/servicehost/unity.v1.xsd">
3 <namespace name="System"/>
4 <namespace name="System.Collections.Generic"/>
5 <namespace name="Implab.Components"/>
6 <namespace name="Implab.ServiceHost.Test.Mock"/>
7
8 <register name="Big" type="Baz+Nut">
9 <property name="Size">
10 <value>5</value>
11 </property>
12 </register>
13 <register name="Mid" type="Baz+Nut">
14 <property name="Size">
15 <value>3</value>
16 </property>
17 </register>
18 <register name="Small" type="Baz+Nut">
19 <property name="Size">
20 <value>1</value>
21 </property>
22 </register>
23 <register type="Baz+Nut">
24 <property name="Size">
25 <value>2</value>
26 </property>
27 </register>
28
29 <!-- register a generic interface mapping to the generic type -->
30 <register type="IBox{}" mapTo="Box{}">
31 <property name="Value">
32 <!-- the dependency type is implied from the property and will be the generic parameter {T} -->
33 <dependency optional="true"/>
34 </property>
35 </register>
36
37 <factory name="Box2" type="BoxFactory{}">
38 </factory>
39
40 <register type="IBox{String}" mapTo="Box{String}">
41 <property name="Name">
42 <value>boxForString</value>
43 </property>
44 </register>
45
46 <register name="Small" type="IBox{}" mapTo="Box{}">
47 <property name="Value">
48 <dependency name="Small" optional="true"/>
49 </property>
50 </register>
51
52 <register type="SetOfBoxes{}">
53 <constructor/>
54 <method name="BoxValues">
55 <!-- only generic parameter or type without unresolved parameters
56 can be used, this is a limitation of Unity container. TODO -->
57 <array itemsType="T">
58 <default />
59 <dependency optional="true"/>
60 <dependency name="Small" optional="true"/>
61 </array>
62 </method>
63 </register>
64
65 </container> No newline at end of file
@@ -0,0 +1,6
1 <?xml version="1.0"?>
2 <Person xmlns="urn:implab:test:model">
3 <FirstName>Trohn</FirstName>
4 <LastName>Javolta</LastName>
5 <Age>88</Age>
6 </Person> No newline at end of file
@@ -0,0 +1,16
1 <?xml version="1.0"?>
2 <container xmlns="http://implab.org/schemas/servicehost/unity.v1.xsd">
3 <namespace name="System"/>
4 <namespace name="System.Collections.Generic"/>
5 <namespace name="Implab.Components"/>
6 <namespace name="Implab.ServiceHost.Test.Mock"/>
7
8 <serialized name="p1" type="Person">
9 <Person xmlns="urn:implab:test:model">
10 <FirstName>Com</FirstName>
11 <LastName>Truise</LastName>
12 <Age>99</Age>
13 </Person>
14 </serialized>
15 <serialized name="p2" type="Person" href="p2.xml"/>
16 </container> No newline at end of file
@@ -0,0 +1,63
1 <?xml version="1.0"?>
2 <container xmlns="http://implab.org/schemas/servicehost/unity.v1.xsd">
3 <namespace name="System"/>
4 <namespace name="System.Collections.Generic"/>
5 <namespace name="Implab.Components"/>
6 <namespace name="Implab.ServiceHost.Test.Mock"/>
7
8 <register name="Baz1" type="Baz">
9 <property name="Numbers">
10 <array>
11 <value>1</value>
12 <value>2</value>
13 <value>3</value>
14 </array>
15 </property>
16 </register>
17
18 <register type="Baz">
19 <property name="Nuts">
20 <array>
21 <dependency/>
22 <dependency name="Big"/>
23 <dependency name="Big"/>
24 <dependency name="Small"/>
25 <dependency name="Mid"/>
26 </array>
27 </property>
28 </register>
29
30 <register name="Big" type="Baz+Nut">
31 <property name="Size">
32 <value>5</value>
33 </property>
34 </register>
35 <register name="Mid" type="Baz+Nut">
36 <property name="Size">
37 <value>3</value>
38 </property>
39 </register>
40 <register name="Small" type="Baz+Nut">
41 <property name="Size">
42 <value>1</value>
43 </property>
44 </register>
45 <register type="Baz+Nut">
46 <property name="Size">
47 <value>2</value>
48 </property>
49 </register>
50 <factory type="BazFactory">
51 <provides name="Baz2" type="Baz"/>
52 </factory>
53
54 <factory name="Baz3" type="BazFactory">
55 <property name="IdGenerator">
56 <dependency/>
57 </property>
58 </factory>
59
60 <factory type="GuidFactory">
61 <singleton/>
62 </factory>
63 </container> No newline at end of file
@@ -0,0 +1,23
1 using System;
2 using System.Collections.Generic;
3
4 namespace Implab.ServiceHost.Test.Mock {
5 public class Baz {
6
7 public Guid Id {
8 get; set;
9 }
10
11 public int[] Numbers {
12 get; set;
13 }
14
15 public Nut[] Nuts {
16 get; set;
17 }
18
19 public class Nut {
20 public int Size { get; set; }
21 }
22 }
23 } No newline at end of file
@@ -0,0 +1,17
1 using System;
2 using Implab.Components;
3
4 namespace Implab.ServiceHost.Test.Mock {
5 public class BazFactory : IFactory<Baz> {
6
7 public Func<Guid> IdGenerator {
8 get; set;
9 }
10
11 Baz IFactory<Baz>.Create() {
12 return new Baz {
13 Id = IdGenerator?.Invoke() ?? Guid.Empty
14 };
15 }
16 }
17 } No newline at end of file
@@ -0,0 +1,13
1 using System;
2 using Implab.Components;
3
4 namespace Implab.ServiceHost.Test.Mock {
5 public class BoxFactory<T> : IFactory<IBox<T>> {
6 public IBox<T> Create() {
7 return new Box<T> {
8 Name = "Creepy sugar"
9 };
10 }
11 }
12
13 } No newline at end of file
@@ -0,0 +1,13
1 namespace Implab.ServiceHost.Test.Mock {
2 public class Box<T> : IBox<T> {
3
4 public string Name { get; set; }
5
6 public T Value { get; set; }
7
8 public T GetBoxValue() {
9 return Value;
10 }
11
12 }
13 } No newline at end of file
@@ -0,0 +1,10
1 using System;
2 using Implab.Components;
3
4 namespace Implab.ServiceHost.Test.Mock {
5 public class GuidFactory : IFactory<Guid> {
6 public Guid Create() {
7 return Guid.NewGuid();
8 }
9 }
10 } No newline at end of file
@@ -0,0 +1,6
1 namespace Implab.ServiceHost.Test.Mock {
2 public interface IBox<T> {
3 string Name { get; }
4 T GetBoxValue();
5 }
6 } No newline at end of file
@@ -0,0 +1,20
1 using System.Xml.Serialization;
2
3 namespace Implab.ServiceHost.Test.Mock
4 {
5 [XmlRoot(Namespace="urn:implab:test:model")]
6 public class Person {
7 public string FirstName { get; set; }
8
9 public string LastName { get; set; }
10
11 public int Age { get; set; }
12
13 [XmlIgnore]
14 public bool AgeSpecified { get; set; }
15
16
17 [XmlElement("Tag")]
18 public string[] Tags { get; set; }
19 }
20 } No newline at end of file
@@ -0,0 +1,21
1 using System;
2 using System.Linq;
3
4 namespace Implab.ServiceHost.Test.Mock {
5 public class SetOfBoxes<T> {
6
7 public Guid Uuid { get; set; }
8
9 public IBox<T>[] Boxes {
10 get; set;
11 }
12
13 public void BoxValues(T[] items) {
14 if (items == null || items.Length == 0)
15 return;
16
17 Boxes = items.Select(x => new Box<T> {Value = x}).ToArray();
18 }
19
20 }
21 } No newline at end of file
@@ -0,0 +1,94
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Linq;
5 using System.Threading;
6 using System.Threading.Tasks;
7 using Implab.Components;
8 using Implab.Diagnostics;
9 using Implab.ServiceHost.Test.Mock;
10 using Implab.ServiceHost.Unity;
11 using Unity;
12 using Xunit;
13
14 namespace Implab.Test {
15
16 public class UnityConfigTest {
17
18 [Fact]
19 public void CreateContainer() {
20 var container = new UnityContainer();
21
22 container.LoadXmlConfiguration(Path.Combine("data","container","empty.xml"));
23 }
24
25 [Fact]
26 public void SimpleServicesContainer() {
27 var container = new UnityContainer();
28
29 container.LoadXmlConfiguration(Path.Combine("data","container","simple.services.xml"));
30
31 // named service registration
32 var baz1 = container.Resolve<Baz>("Baz1");
33
34 Assert.Equal(new [] {1,2,3}, baz1.Numbers);
35
36 // default service registration
37 var baz = container.Resolve<Baz>();
38
39 Assert.Equal(new [] {2,5,5,1,3}, baz.Nuts.Select(x => x.Size));
40
41 // ServiceFactory registered without a name
42 // explicitly provides 'Baz2' service
43 var baz2 = container.Resolve<Baz>("Baz2");
44
45 // ServiceFactory registered with name 'Baz3'
46 // provides by default the service registration with same name
47 var baz3 = container.Resolve<Baz>("Baz3");
48
49 // This factory uses GuidGenerator registration
50 // to generate a new id value
51 Assert.NotEqual(Guid.Empty, baz3.Id);
52 }
53
54 [Fact]
55 public void GenericServicesContainer() {
56 var container = new UnityContainer();
57 container.LoadXmlConfiguration(Path.Combine("data","container","generic.services.xml"));
58
59 // resolve using a generig interface mapping
60 var box = container.Resolve<IBox<Baz.Nut>>();
61
62 Assert.NotNull(box.GetBoxValue());
63
64 // registered generic defines dependency of type {T}
65 // in this case it should resolve to the default Nut with Size=2
66 Assert.Equal(box.GetBoxValue().Size,2);
67
68 // generic factory which provides generic services
69 var box2 = container.Resolve<IBox<Baz.Nut>>();
70
71 var set1 = container.Resolve<SetOfBoxes<Baz.Nut>>();
72
73 Assert.Equal(new int?[] {null,2,1}, set1.Boxes?.Select(x => x.GetBoxValue()?.Size));
74 }
75
76 [Fact]
77 public void SerializedInstances() {
78 var container = new UnityContainer();
79 container.LoadXmlConfiguration(Path.Combine("data","container","serialized.instances.xml"));
80
81 var p1 = container.Resolve<Person>("p1");
82 var p2 = container.Resolve<Person>("p2");
83
84 Assert.Equal("Com", p1.FirstName);
85 Assert.True(p1.AgeSpecified);
86 Assert.Equal(99, p1.Age);
87
88 Assert.Equal("Javolta", p2.LastName);
89 Assert.True(p2.AgeSpecified);
90 Assert.Equal(88, p2.Age);
91 }
92
93 }
94 } No newline at end of file
@@ -0,0 +1,36
1 <Project Sdk="Microsoft.NET.Sdk">
2
3 <PropertyGroup>
4 <Authors>Sergey Smirnov</Authors>
5 <Title>Implab.ServiceHost</Title>
6 <Description>The configurable application host.
7 Provides simple and flexible Xml configuration for UnityContainer.
8 </Description>
9 <Copyright>2012-2018 Sergey Smirnov</Copyright>
10 <Version>1.0.3</Version>
11 <PackageLicenseUrl>https://bitbucket.org/wozard/implabnet/src/v3/Implab/license.txt</PackageLicenseUrl>
12 <PackageProjectUrl>https://bitbucket.org/wozard/implabnet</PackageProjectUrl>
13 <RepositoryUrl>https://bitbucket.org/wozard/implabnet</RepositoryUrl>
14 <RepositoryType>mercurial</RepositoryType>
15 <PackageTags>Implab;Xml configuration;IoC;Unity container</PackageTags>
16 </PropertyGroup>
17
18
19 <PropertyGroup Condition="'$(OSTYPE)'=='linux'">
20 <TargetFrameworks>netcoreapp2.0;net46</TargetFrameworks>
21 <FrameworkPathOverride Condition="'$(TargetFramework)'=='net46'">/usr/lib/mono/4.5/</FrameworkPathOverride>
22 </PropertyGroup>
23
24 <PropertyGroup Condition="'$(OSTYPE)'=='windows'">
25 <TargetFrameworks>netcoreapp2.0;net46</TargetFrameworks>
26 </PropertyGroup>
27
28 <ItemGroup>
29 <PackageReference Include="Unity" Version="5.8.6" />
30 </ItemGroup>
31
32 <ItemGroup>
33 <ProjectReference Include="..\Implab\Implab.csproj" />
34 </ItemGroup>
35
36 </Project>
@@ -0,0 +1,113
1 # XML Конфигурация IoC контейнера
2
3 Библиоетка создавалась для загрузки и применения конфигурации к IoC контейнеру, она не предназначена для конфигурирования
4 контейнера во время выполнения, большинство контейнеров уже обладают данным функционалом.
5
6 На данный момент поддерживается единственный вид контейнера - [Unity Container](https://unitycontainer.github.io/)
7
8 Unity уже обладает средствами загрузки конфигурации из XML, данная библиотека реализует аналогичный функционал, кроме того, позволяет решать следующие задачи:
9
10 - Конфигурация является простым Xml документом, который можно получить из любого источика и не ограничивается `.config` файлами приложения
11 - Включение существующе конфигурации `<include href='config.xml'/>` в текущую
12 - Поддержка сериализованных объектов в качестве регистраций сервисов и параметров
13 - Поддержка специфиакции генериков любой вложенности, например `Dictionary{Foo,Bar{Int32}}`
14 - Поддержка фабрик в XML конфигурации
15 - Расширение схемы XML конфигурации собственными элементами
16
17 ## Общая архитектура
18
19 Пространство имен `Implab.ServiceHost.Unity` содержит в себе классы для загрузки и применения XML конфигурации к IoC контейнеру.
20
21 Применение конфигурации к контейнеру состоит из следующих основных шагов:
22
23 1. Настраивается схема `ContainerConfigurationSchema` XML конфигурации контейнера
24 2. Загружается документ и десереализуется в виде `ContainerElement`
25 3. Создается `ContainerBuilder` при помощи которого применяются настройки из `ContainerElement` к контейнеру
26
27 Схема `ContainerConfigurationSchema` определяет элементы документа, которые могут быть использованы в конфигурации контейнера, позволяет создать `XmlSerializer`, который используется для загрузки конфигурации.
28
29 `ContainerBuilder` - основной класс, который используется для применения конфигурации к контейнеру, он добавляет записи регистрации сервисов из конфигурации в контейнер.
30
31 `ContainerElement` - Конфигурация контейнера, которая загружается из документа, состоит из директив для `ContainerBuilder`, а также из записей регистрации сервисов.
32
33 В библиотеки приняты следующие правила именования классов:
34
35 - `***Builder` используются для применения конфигурации к контейнеру,
36 - `***Element` содержат информацию о конфигурации и десериализуются из исходного документа.
37
38 ## Структура конфигурации контейнера
39
40 Элемент верхнего уровня всегда `container`, он используется для хранения набора элеметов, которые распознаются и выполняются `ContainerBuilder`.
41
42 Все элементы, входящие в контейнер наследуются от абстрактного класса `ContainerItemElement`,
43 который позволяет получить текущий `ContainerBuilder` и выполнить над ним какие-либо действия.
44
45 Основные элементы конфигурации контенейра
46
47 - `<include href='config.xml'/>` - включение конфигурации из указанного места
48 - `<namespace name='My.App'/>` - добавление пространства имен для поиска типов
49 - `<register type='MyGenericType{}'/>` - добавление в контейнер регистрации типа ``My.App.MyGenericType`1``
50 - `<factory type='IFactory{Foo}' mapTo ='MyFactory'/>` - фабрика, регистрирует свой тип, а также тип `Foo`
51 - `<serialized />` - сериализованный экземпляр объекта, использует `XmlSerializer` для десериализации
52 - `<value />` - значение объекта в виде строки, используется для простых типов
53
54 Полный набор элементов, доступных для использования в контейнере определяет схема `ContainerConfigurationSchema`,
55 разработчик может расширить контейнер совими собственными элементами зарегистрировав их в схеме.
56
57 ### register
58
59 О
60
61
62 Например, мы используем компоненту `MyHttpClient` для загрузки данных
63
64 ```xml
65 <register type="IClient" mapTo="MyHttpClient">
66 <property name="proxy">
67 <value>socks5://proxy1.my.company</value>
68 </property>
69 </register>
70 ```
71
72 При частом использовании можно сделать описание конфигурации несколько проще,
73 описав новый эелемент конфигурации
74
75 ```csharp
76 public class MyHttpClientElement : ContainerItemElement {
77
78 public string Proxy { get; set; }
79
80 public override void Visit(ContainerBuilder builder) {
81 // создаем описание элемента
82 var registration = new RegistrationElement {
83 RegistrationType = "IClient",
84 ImplementationType = "My.App.MyHttpClient",
85 Injectors = new [] {
86 new PropertyInjectionElement {
87 Name = "Proxy",
88 Value = ValueParameterElement {
89 Value = Proxy
90 }
91 }
92 }
93 };
94
95 // применяем созданное описание к контейнеру
96 builder.Visit(registration)
97 }
98 }
99 ```
100
101 Регистрируем новый элемент в схеме
102
103 ```csharp
104 schema.RegisterContainerElement<MyHttpClientElement>("http");
105 ```
106
107 Используем новый элемент в конфигурации
108
109 ```xml
110 <http>
111 <proxy>socks5://proxy1.my.company</propxy>
112 </http>
113 ``` No newline at end of file
@@ -0,0 +1,12
1 namespace Implab.ServiceHost.Unity {
2
3 /// <summary>
4 /// Базовый класс для элеметов контейнера.
5 /// </summary>
6 /// <remarks>
7 /// XmlSerializer требует использования классов при объявлении свойств, которые будут сериализованы <see cref="ContainerElement.Items"/>
8 /// </remarks>
9 public abstract class AbstractContainerItem {
10 public abstract void Visit(ContainerBuilder builder);
11 }
12 } No newline at end of file
@@ -0,0 +1,12
1 using System;
2 using System.Xml.Serialization;
3
4 namespace Implab.ServiceHost.Unity {
5 public abstract class AbstractInjectionParameter : IInjectionParameter {
6
7 [XmlAttribute("type")]
8 public string TypeName { get; set; }
9
10 public abstract void Visit(InjectionParameterBuilder builder);
11 }
12 } No newline at end of file
@@ -0,0 +1,10
1 using System;
2
3 namespace Implab.ServiceHost.Unity {
4 /// <summary>
5 /// Base class for injections, each injection is applied to the type registration context.
6 /// </summary>
7 public abstract class AbstractMemberInjection : ITypeMemberInjection {
8 public abstract void Visit(TypeRegistrationBuilder builder);
9 }
10 } No newline at end of file
@@ -0,0 +1,48
1 using System;
2 using System.Xml.Serialization;
3 using Unity.Lifetime;
4 using Unity.Registration;
5
6 namespace Implab.ServiceHost.Unity
7 {
8 /// <summary>
9 /// Базовая информаци о регистрации в контейнере: тип, имя и время жизни
10 /// </summary>
11 public abstract class AbstractRegistration : AbstractContainerItem, IRegistration {
12
13 /// <summary>
14 /// An optional name for a registration in the container
15 /// </summary>
16 [XmlAttribute("name")]
17 public string Name {
18 get; set;
19 }
20
21 [XmlElement("signleton", typeof(SingletonLifetimeElement))]
22 [XmlElement("context", typeof(ContextLifetimeElement))]
23 [XmlElement("container", typeof(ContainerLifetimeElement))]
24 [XmlElement("hierarchy", typeof(HierarchicalLifetimeElement))]
25 public LifetimeElement Lifetime {get; set;}
26
27 /// <summary>
28 /// A type specification for the service registration,
29 /// </summary>
30 [XmlAttribute("type")]
31 public string RegistrationType { get; set; }
32
33 public virtual LifetimeManager GetLifetime(ContainerBuilder builder) {
34 return Lifetime?.GetLifetime(builder);
35 }
36
37 public virtual Type GetRegistrationType(Func<string,Type> resolver) {
38 return resolver(RegistrationType);
39 }
40
41 public virtual Type GetRegistrationType(ContainerBuilder builder) {
42 return builder.ResolveType(RegistrationType);
43 }
44
45
46
47 }
48 } No newline at end of file
@@ -0,0 +1,20
1 using System.Xml.Serialization;
2
3 namespace Implab.ServiceHost.Unity
4 {
5 public class ArrayParameterElement : AbstractInjectionParameter {
6
7 [XmlAttribute("itemsType")]
8 public string ItemsType { get; set; }
9
10 [XmlElement("dependency", typeof(DependencyParameterElement))]
11 [XmlElement("value", typeof(ValueParameterElement))]
12 [XmlElement("serialized", typeof(SerializedParameterElement))]
13 [XmlElement("default", typeof(DefaultParameterElement))]
14 public AbstractInjectionParameter[] Items { get; set; }
15
16 public override void Visit(InjectionParameterBuilder builder) {
17 builder.Visit(this);
18 }
19 }
20 } No newline at end of file
@@ -0,0 +1,57
1 using System;
2 using System.Text;
3
4 namespace Implab.ServiceHost.Unity {
5 public class ArrayTypeReference : TypeReference {
6 public int Rank { get; private set; }
7
8 public TypeReference ItemsType { get; private set; }
9
10 public override string Name {
11 get {
12 return ItemsType.Name;
13 }
14 }
15
16 public override string ClrName {
17 get {
18 return new StringBuilder()
19 .Append(ItemsType.ClrName)
20 .Append("[")
21 .Append(',', Rank - 1)
22 .Append("]")
23 .ToString();
24 }
25 }
26
27 public override string Namespace {
28 get {
29 return ItemsType.Namespace;
30 }
31 }
32
33 public override int GenericParametersCount {
34 get {
35 return 0;
36 }
37 }
38
39 internal ArrayTypeReference(TypeReference itemsType, int rank) {
40 ItemsType = itemsType;
41 Rank = rank;
42 }
43
44 internal override void Visit(TypeResolutionContext visitor) {
45 visitor.Visit(this);
46 }
47
48 override public string ToString() {
49 return new StringBuilder()
50 .Append(ItemsType.ToString())
51 .Append('[')
52 .Append(',', Rank - 1)
53 .Append(']')
54 .ToString();
55 }
56 }
57 } No newline at end of file
@@ -0,0 +1,14
1 using System.Xml.Serialization;
2
3 namespace Implab.ServiceHost.Unity
4 {
5 [XmlRoot("assembly", Namespace = Schema.ContainerConfigurationNamespace)]
6 public class AssemblyElement : AbstractContainerItem {
7 [XmlAttribute("name")]
8 public string AssemblyName { get; set; }
9
10 public override void Visit(ContainerBuilder builder) {
11 builder.AddAssembly(AssemblyName);
12 }
13 }
14 } No newline at end of file
@@ -0,0 +1,17
1 using System.Xml.Serialization;
2
3 namespace Implab.ServiceHost.Unity {
4 public class ConstructorInjectionElement : AbstractMemberInjection {
5
6 [XmlElement("dependency", typeof(DependencyParameterElement))]
7 [XmlElement("value", typeof(ValueParameterElement))]
8 [XmlElement("serialized", typeof(SerializedParameterElement))]
9 [XmlElement("default", typeof(DefaultParameterElement))]
10 [XmlElement("array", typeof(ArrayParameterElement))]
11 public AbstractInjectionParameter[] Parameters { get; set; }
12
13 public override void Visit(TypeRegistrationBuilder builder) {
14 builder.Visit(this);
15 }
16 }
17 } No newline at end of file
@@ -0,0 +1,161
1 using System;
2 using System.IO;
3 using System.Reflection;
4 using Implab.Diagnostics;
5 using Unity;
6
7 namespace Implab.ServiceHost.Unity {
8 using Log = Trace<ContainerBuilder>;
9
10 public class ContainerBuilder {
11
12 readonly TypeResolver m_resolver;
13
14 readonly IUnityContainer m_container;
15
16 readonly ContainerConfigurationSchema m_schema;
17
18 Uri m_location;
19
20 public IUnityContainer Container {
21 get {
22 return m_container;
23 }
24 }
25
26 public ContainerBuilder() : this(null, null) {
27 }
28
29 public ContainerBuilder(IUnityContainer container, ContainerConfigurationSchema schema) {
30 m_container = container ?? new UnityContainer();
31 m_resolver = new TypeResolver();
32 m_schema = schema ?? ContainerConfigurationSchema.Default;
33 }
34
35 public Type ResolveType(string typeReference) {
36 var resolved = string.IsNullOrEmpty(typeReference) ? null : m_resolver.Resolve(typeReference, true);
37 Log.Debug("ResolveType('{0}'): {1}", typeReference, resolved?.FullName);
38 return resolved;
39 }
40
41 public void Visit(ITypeRegistration registration) {
42 Safe.ArgumentNotNull(registration, nameof(registration));
43
44 var registrationType = registration.GetRegistrationType(this);
45 var implementationType = registration.GetImplementationType(this) ?? registrationType;
46
47 if (registrationType == null)
48 throw new Exception($"A type must be specified for the registration {registration.Name}");
49
50 var builder = new TypeRegistrationBuilder(
51 m_resolver,
52 registrationType,
53 implementationType,
54 this
55 );
56
57 builder.Lifetime = registration.GetLifetime(this);
58
59 if (registration.MemberInjections != null) {
60 foreach(var member in registration.MemberInjections)
61 member.Visit(builder);
62 }
63
64 m_container.RegisterType(
65 builder.RegistrationType,
66 builder.ImplementationType,
67 registration.Name,
68 builder.Lifetime,
69 builder.Injections
70 );
71 }
72
73 public void Visit(IInstanceRegistration registration) {
74 Safe.ArgumentNotNull(registration, nameof(registration));
75
76 var registrationType = registration.GetRegistrationType(this);
77
78 var builder = new InstanceRegistrationBuilder (
79 m_resolver,
80 registrationType,
81 this
82 );
83
84 builder.Lifetime = registration.GetLifetime(this);
85
86 if (registration.MemberInjections != null) {
87 foreach(var member in registration.MemberInjections)
88 member.Visit(builder.ValueBuilder);
89 }
90
91 if (builder.RegistrationType == null && builder.ValueBuilder.ValueType == null)
92 throw new Exception($"A type must be specified for the registration {registration.Name}");
93
94 m_container.RegisterInstance(
95 builder.RegistrationType ?? builder.ValueBuilder.ValueType,
96 registration.Name,
97 builder.ValueBuilder.Value,
98 builder.Lifetime
99 );
100 }
101
102 public void AddNamespace(string ns) {
103 m_resolver.AddNamespace(ns);
104 Log.Log($"AddNamespace: {ns}");
105 }
106
107 public void AddAssembly(string assembly) {
108 var asm = Assembly.Load(assembly);
109 Log.Log($"AddAssembly: {assembly} -> {asm.FullName}");
110 }
111
112 /// <summary>
113 /// Includes the confguration. Creates a new <see cref="ContainerBuilder"/>,
114 /// and loads the configuration to it. The created builder will share the
115 /// container and will have its own isolated type resolver.
116 /// </summary>
117 /// <param name="file">A path to configuration relative to the current configuration.</param>
118 public void Include(string file) {
119 var includeContext = new ContainerBuilder(m_container, m_schema);
120
121 if (m_location != null) {
122 var uri = new Uri(m_location, file);
123 includeContext.LoadConfig(uri);
124 } else {
125 includeContext.LoadConfig(file);
126 }
127 }
128
129 /// <summary>
130 /// Resolves a path ralatively to the current container configuration location.
131 /// </summary>
132 /// <param name="location">A path yto resolve</param>
133 /// <returns>Resolved Uri fot the specified location</returns>
134 public Uri MakeLocationUri(string location) {
135 return m_location != null ? new Uri(m_location, location) : new Uri(location);
136 }
137
138 /// <summary>
139 /// Loads a configuration from the specified local file.
140 /// </summary>
141 /// <param name="file">The path to the configuration file.</param>
142 public void LoadConfig(string file) {
143 Safe.ArgumentNotEmpty(file, nameof(file));
144
145 LoadConfig(new Uri(Path.GetFullPath(file)));
146 }
147
148 public void LoadConfig(Uri location) {
149 Safe.ArgumentNotNull(location, nameof(location));
150
151 Log.Log($"LoadConfig {location}");
152 Safe.ArgumentNotNull(location, nameof(location));
153
154 m_location = location;
155
156 var config = m_schema.LoadConfig(location.ToString());
157 config.Visit(this);
158 }
159
160 }
161 } No newline at end of file
@@ -0,0 +1,70
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Reflection;
5 using System.Xml;
6 using System.Xml.Serialization;
7 using Implab.Components;
8
9 namespace Implab.ServiceHost.Unity {
10 public class ContainerConfigurationSchema {
11
12 public static ContainerConfigurationSchema Default { get; private set; } = CreateDefault();
13
14 readonly LazyAndWeak<XmlSerializer> m_seralizer;
15
16 readonly XmlAttributeOverrides m_overrides = new XmlAttributeOverrides();
17
18 readonly XmlAttributes m_containerItems = new XmlAttributes();
19
20 public XmlSerializer Serializer {
21 get {
22 return m_seralizer.Value;
23 }
24 }
25
26 public ContainerConfigurationSchema() {
27 m_overrides.Add(typeof(ContainerElement), nameof(ContainerElement.Items), m_containerItems);
28
29 m_seralizer = new LazyAndWeak<XmlSerializer>(() => new XmlSerializer(typeof(ContainerElement), m_overrides));
30 }
31
32 public void RegisterContainerElement(Type type, string name) {
33 Safe.ArgumentNotNull(type, nameof(type));
34 Safe.ArgumentNotEmpty(name, nameof(name));
35
36 if(!type.IsSubclassOf(typeof(AbstractContainerItem)))
37 throw new Exception($"RegisterContainerElement '{name}': {type} must be subclass of {typeof(AbstractContainerItem)}");
38
39 m_containerItems.XmlElements.Add(
40 new XmlElementAttribute(name, type)
41 );
42 }
43
44 public void RegisterContainerElement<T>(string name) where T : AbstractContainerItem {
45 RegisterContainerElement(typeof(T), name);
46 }
47
48 public ContainerElement LoadConfig(string uri) {
49 using (var reader = XmlReader.Create(uri)) {
50 return (ContainerElement)Serializer.Deserialize(reader);
51 }
52 }
53
54 static ContainerConfigurationSchema CreateDefault() {
55 var schema = new ContainerConfigurationSchema();
56
57 schema.RegisterContainerElement<RegisterElement>("register");
58 schema.RegisterContainerElement<FactoryElement>("factory");
59 schema.RegisterContainerElement<SerializedElement>("serialized");
60 schema.RegisterContainerElement<ValueElement>("value");
61 schema.RegisterContainerElement<IncludeElement>("include");
62 schema.RegisterContainerElement<AssemblyElement>("assembly");
63 schema.RegisterContainerElement<NamespaceElement>("namespace");
64
65 return schema;
66 }
67
68
69 }
70 } No newline at end of file
@@ -0,0 +1,19
1 using Implab.Xml;
2 using System.Collections.Generic;
3 using System.Xml;
4 using System.Xml.Schema;
5 using System.Xml.Serialization;
6
7 namespace Implab.ServiceHost.Unity {
8 [XmlRoot("container", Namespace = Schema.ContainerConfigurationNamespace)]
9 public class ContainerElement : AbstractContainerItem {
10
11 public List<AbstractContainerItem> Items { get; set; } = new List<AbstractContainerItem>();
12
13 public override void Visit(ContainerBuilder context) {
14 if (Items != null)
15 foreach(var item in Items)
16 item.Visit(context);
17 }
18 }
19 } No newline at end of file
@@ -0,0 +1,12
1 using Unity.Lifetime;
2
3 namespace Implab.ServiceHost.Unity
4 {
5 public class ContainerLifetimeElement : LifetimeElement {
6 public override LifetimeManager GetLifetime(ContainerBuilder builder) {
7 return new ContainerControlledLifetimeManager();
8 }
9
10
11 }
12 } No newline at end of file
@@ -0,0 +1,10
1 using Unity.Lifetime;
2
3 namespace Implab.ServiceHost.Unity
4 {
5 public class ContextLifetimeElement : LifetimeElement {
6 public override LifetimeManager GetLifetime(ContainerBuilder builder) {
7 return new PerResolveLifetimeManager();
8 }
9 }
10 } No newline at end of file
@@ -0,0 +1,13
1 namespace Implab.ServiceHost.Unity
2 {
3 public class DefaultParameterElement : AbstractInjectionParameter {
4 public string Value {
5 get { return null; }
6 }
7
8 public override void Visit(InjectionParameterBuilder builder) {
9 var type = builder.ResolveInjectedValueType(TypeName);
10 builder.SetValue(type, Safe.CreateDefaultValue(type));
11 }
12 }
13 } No newline at end of file
@@ -0,0 +1,17
1 using System.Xml.Serialization;
2
3 namespace Implab.ServiceHost.Unity {
4 public class DependencyParameterElement : AbstractInjectionParameter {
5
6 [XmlAttribute("name")]
7 public string DependencyName { get; set; }
8
9 [XmlAttribute("optional")]
10 public bool Optional { get; set; }
11
12 public override void Visit(InjectionParameterBuilder builder) {
13 var type = builder.ResolveInjectedValueType(TypeName);
14 builder.SetDependency(type, DependencyName, Optional);
15 }
16 }
17 } No newline at end of file
@@ -0,0 +1,78
1 using System;
2 using System.Collections.Generic;
3 using System.Reflection;
4 using Implab.Components;
5 using Unity;
6 using Unity.Injection;
7 using Unity.Lifetime;
8
9 namespace Implab.ServiceHost.Unity {
10 public class FactoryActivator : ITypeRegistration {
11
12 class FactoryInjector : ITypeMemberInjection {
13 public InjectionFactory Factory { get; set; }
14 public void Visit(TypeRegistrationBuilder builder) {
15 builder.AddInjectionMember(Factory);
16 }
17 }
18
19
20 public Type FactoryType { get; set; }
21
22 public string FactoryName { get; set; }
23
24 public Type RegistrationType { get; set; }
25
26 public LifetimeManager Lifetime { get; set; }
27
28 public IEnumerable<ITypeMemberInjection> MemberInjections {
29 get {
30 if (RegistrationType == null)
31 throw new Exception($"RegistrationType must be specified");
32 if (!typeof(IFactory<>).MakeGenericType(RegistrationType).IsAssignableFrom(FactoryType))
33 throw new Exception($"The factory {FactoryType} can't be used to create {RegistrationType} instances");
34
35 if (FactoryType.ContainsGenericParameters) {
36 yield return new FactoryInjector {
37 Factory = CreateDynamicInjectionFactory(FactoryName)
38 };
39 } else {
40 yield return new FactoryInjector {
41 Factory = (InjectionFactory)GetType()
42 .GetMethod(nameof(CreateInjectionFactory), BindingFlags.Static | BindingFlags.NonPublic)
43 .MakeGenericMethod(FactoryType, RegistrationType)
44 .Invoke(null, new [] { FactoryName })
45 };
46 }
47 }
48 }
49
50 public string Name { get; set; }
51
52 public Type GetRegistrationType(ContainerBuilder builder) {
53 return RegistrationType;
54 }
55
56 public LifetimeManager GetLifetime(ContainerBuilder builder) {
57 return Lifetime;
58 }
59
60 public Type GetImplementationType(ContainerBuilder builder) {
61 return null;
62 }
63
64 /// <summary>
65 /// Указывает зависимость, реализующую интерфейс <see cref="IFactory{TObj}"/>,
66 /// которая будет использоваться в качестве фабрики для создания объектов
67 /// </summary>
68 /// <param name="dependencyName"></param>
69 static InjectionFactory CreateInjectionFactory<TFac, TObj>(string dependencyName) where TFac : IFactory<TObj> {
70
71 return new InjectionFactory(c => c.Resolve<TFac>(dependencyName).Create());
72 }
73
74 static InjectionFactory CreateDynamicInjectionFactory(string dependencyName) {
75 return new InjectionFactory((c,t,name) => ((IFactory<object>)c.Resolve(t, dependencyName)).Create());
76 }
77 }
78 } No newline at end of file
@@ -0,0 +1,73
1 using System;
2 using System.Xml.Serialization;
3 using Implab.Components;
4
5 namespace Implab.ServiceHost.Unity {
6 /// <summary>
7 /// Расширяет стандартную регистрацию типа до фабрики, вместе с регистрацией
8 /// самой фабрики создаются регистрации сервисов, которые она предоставляет.
9 /// </summary>
10 public class FactoryElement : RegisterElement, ITypeRegistration {
11
12 /// <summary>
13 /// Записи о сервисах, которые создаются данной фабрикой.
14 /// </summary>
15 /// <remarks>
16 /// Сервисы, которые указаны в регистарциях они должны соответсвовать тому,
17 /// что фабрика возвращает, но это остается на откуп контейнера
18 /// </remarks>
19 [XmlElement("provides")]
20 public ProvidesElement[] Provides { get; set; }
21
22 /// <summary>
23 /// Переопределяет стандарное поведение регистрации типа в контейнере,
24 /// дополняя его регистрацией фабричных методов для получения типов.
25 /// </summary>
26 /// <param name="builder">Объект для конфигурирования контейнера.</param>
27 public override void Visit(ContainerBuilder builder) {
28 var factoryType = GetRegistrationType(builder.ResolveType);
29
30 base.Visit(builder);
31
32 if (Provides != null && Provides.Length > 0) {
33 // если регистрации явно заданы, используеися информация из них
34 foreach(var item in Provides) {
35 var activator = new FactoryActivator {
36 Name = item.RegistrationName,
37 RegistrationType = builder.ResolveType(item.RegistrationType),
38 FactoryName = Name,
39 FactoryType = factoryType,
40 Lifetime = item.Lifetime?.GetLifetime(builder)
41 };
42 builder.Visit(activator);
43 }
44 } else {
45 // если регистрация явно не задана, в качестве сервиса для регистрации
46 // используется тип создаваемый фабрикой, который будет добавлен в контейнер
47 // с темже именем, что и сама фабрика (разные типы могут иметь одно имя для регистрации)
48 var providedType = (
49 factoryType.IsGenericType && factoryType.GetGenericTypeDefinition() == typeof(IFactory<>) ?
50 factoryType :
51 factoryType.GetInterface(typeof(IFactory<>).FullName)
52 )?
53 .GetGenericArguments()[0];
54
55 // не удалось определеить тип
56 if (providedType == null)
57 throw new ArgumentException("Failed to determine a type provided by the factory");
58
59 if (providedType.IsGenericParameter)
60 throw new ArgumentException("Can't register a generic type paramter as a service");
61
62 var activator = new FactoryActivator {
63 Name = Name,
64 RegistrationType = providedType,
65 FactoryName = Name,
66 FactoryType = factoryType
67 };
68
69 builder.Visit(activator);
70 }
71 }
72 }
73 } No newline at end of file
@@ -0,0 +1,10
1 using Unity.Lifetime;
2
3 namespace Implab.ServiceHost.Unity
4 {
5 public class HierarchicalLifetimeElement : LifetimeElement {
6 public override LifetimeManager GetLifetime(ContainerBuilder builder) {
7 return new HierarchicalLifetimeManager();
8 }
9 }
10 } No newline at end of file
@@ -0,0 +1,5
1 namespace Implab.ServiceHost.Unity {
2 public interface IInjectionParameter {
3 void Visit(InjectionParameterBuilder builder);
4 }
5 } No newline at end of file
@@ -0,0 +1,8
1 using System.Collections.Generic;
2
3 namespace Implab.ServiceHost.Unity {
4 public interface IInstanceRegistration : IRegistration {
5
6 IEnumerable<IInjectionParameter> MemberInjections { get; }
7 }
8 } No newline at end of file
@@ -0,0 +1,12
1 using System;
2 using Unity.Lifetime;
3
4 namespace Implab.ServiceHost.Unity {
5 public interface IRegistration {
6 string Name { get; }
7
8 Type GetRegistrationType(ContainerBuilder builder);
9
10 LifetimeManager GetLifetime(ContainerBuilder builder);
11 }
12 } No newline at end of file
@@ -0,0 +1,6
1 namespace Implab.ServiceHost.Unity
2 {
3 public interface ITypeMemberInjection {
4 void Visit(TypeRegistrationBuilder builder);
5 }
6 } No newline at end of file
@@ -0,0 +1,10
1 using System;
2 using System.Collections.Generic;
3
4 namespace Implab.ServiceHost.Unity {
5 public interface ITypeRegistration : IRegistration {
6 Type GetImplementationType(ContainerBuilder builder);
7
8 IEnumerable<ITypeMemberInjection> MemberInjections { get; }
9 }
10 } No newline at end of file
@@ -0,0 +1,13
1 using System.Xml.Serialization;
2
3 namespace Implab.ServiceHost.Unity {
4 [XmlRoot("include", Namespace = Schema.ContainerConfigurationNamespace)]
5 public class IncludeElement : AbstractContainerItem {
6 [XmlAttribute("href")]
7 public string Href { get; set; }
8
9 public override void Visit(ContainerBuilder builder) {
10 builder.Include(Href);
11 }
12 }
13 } No newline at end of file
@@ -0,0 +1,142
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.ComponentModel;
5 using System.Linq;
6 using System.Xml.Serialization;
7 using Unity.Injection;
8
9 namespace Implab.ServiceHost.Unity {
10
11 public class InjectionParameterBuilder {
12
13 readonly TypeResolver m_resolver;
14
15 public Type DefaultType { get; private set; }
16
17 public Type ValueType { get; private set; }
18
19 public ContainerBuilder Root { get; private set; }
20
21 object m_value;
22
23 public object Value {
24 get {
25 if (!ValueSpecified)
26 throw new InvalidOperationException("The regular value must be set (dependency or array are not situable in this context)");
27 return m_value;
28 }
29 }
30
31 public bool ValueSpecified { get; private set; }
32
33 InjectionParameterValue m_injection;
34
35 public InjectionParameterValue Injection {
36 get {
37 if (m_injection == null)
38 throw new InvalidOperationException("The injection parameter is not specified");
39 return m_injection;
40 }
41 }
42
43 public bool InjectionSpecified {
44 get { return m_injection != null; }
45 }
46
47 internal InjectionParameterBuilder(TypeResolver resolver, Type defaultType, ContainerBuilder root) {
48 m_resolver = resolver;
49 DefaultType = defaultType;
50 Root = root;
51 }
52
53 public Type ResolveInjectedValueType(string typeSpec) {
54 if (string.IsNullOrEmpty(typeSpec)) {
55 if (DefaultType == null)
56 throw new Exception("The type must be specified");
57 return DefaultType;
58 }
59 return m_resolver.Resolve(typeSpec, true);
60 }
61
62 public Type ResolveType(string typeSpec) {
63 return string.IsNullOrEmpty(typeSpec) ? null : m_resolver.Resolve(typeSpec, true);
64 }
65
66 public void SetValue(Type type, object value) {
67 Safe.ArgumentNotNull(type, nameof(type));
68
69 ValueType = type;
70 m_value = value;
71 ValueSpecified = true;
72
73 m_injection = new InjectionParameter(type, value);
74 }
75
76 public void SetDependency(Type type, string name, bool optional) {
77 Safe.ArgumentNotNull(type, nameof(type));
78
79 ValueType = type;
80 ValueSpecified = false;
81 m_value = null;
82
83 m_injection = optional ?
84 type.IsGenericParameter ?
85 new OptionalGenericParameter(type.Name, name)
86 : (InjectionParameterValue)new OptionalParameter(type, name)
87 : new ResolvedParameter(type, name);
88 }
89
90 internal void Visit(ArrayParameterElement arrayParameter) {
91 Type itemsType = null;
92 var arrayType = string.IsNullOrEmpty(arrayParameter.TypeName) ? null : ResolveType(arrayParameter.TypeName);
93
94 if (arrayType == null)
95 arrayType = DefaultType;
96
97
98 if (!string.IsNullOrEmpty(arrayParameter.ItemsType)) {
99 itemsType = ResolveType(arrayParameter.ItemsType);
100 arrayType = itemsType.MakeArrayType();
101 } else {
102 itemsType = GetItemsType(arrayType);
103 }
104
105 if (itemsType == null)
106 throw new Exception("Failed to determine array elements type");
107
108 InjectionParameterValue[] injections = (arrayParameter.Items ?? new AbstractInjectionParameter[0])
109 .Select(x => {
110 var builder = new InjectionParameterBuilder(m_resolver, itemsType, Root);
111 x.Visit(builder);
112 return builder.Injection;
113 })
114 .ToArray();
115
116 m_injection = itemsType.IsGenericParameter ?
117 (InjectionParameterValue)new GenericResolvedArrayParameter(itemsType.Name, injections) :
118 new ResolvedArrayParameter(itemsType, injections);
119
120 ValueType = arrayType;
121 m_value = null;
122 ValueSpecified = false;
123 }
124
125 Type GetItemsType(Type collectionType) {
126 if (collectionType == null)
127 return null;
128
129 Type itemsType = null;
130
131 if (collectionType.IsGenericType && collectionType.GetGenericTypeDefinition() == typeof(IEnumerable<>)) {
132 itemsType = collectionType.GetGenericArguments()[0];
133 } else if (collectionType == typeof(IEnumerable)) {
134 itemsType = typeof(object);
135 } else {
136 itemsType = collectionType.GetInterface(typeof(IEnumerable<>).FullName)?.GetGenericArguments()[0];
137 }
138
139 return itemsType;
140 }
141 }
142 } No newline at end of file
@@ -0,0 +1,13
1 using System;
2
3 namespace Implab.ServiceHost.Unity
4 {
5 public class InstanceRegistrationBuilder : RegistrationBuilder {
6
7 public InjectionParameterBuilder ValueBuilder { get; private set; }
8
9 internal InstanceRegistrationBuilder(TypeResolver typeResolver, Type registrationType, ContainerBuilder root) : base(registrationType, root) {
10 ValueBuilder = new InjectionParameterBuilder(typeResolver, registrationType, root);
11 }
12 }
13 } No newline at end of file
@@ -0,0 +1,7
1 using Unity.Lifetime;
2
3 namespace Implab.ServiceHost.Unity {
4 public abstract class LifetimeElement {
5 public abstract LifetimeManager GetLifetime(ContainerBuilder builder);
6 }
7 } No newline at end of file
@@ -0,0 +1,20
1 using System.Xml.Serialization;
2
3 namespace Implab.ServiceHost.Unity {
4 public class MethodInjectionElement : AbstractMemberInjection {
5
6 [XmlAttribute("name")]
7 public string Name { get; set; }
8
9 [XmlElement("dependency", typeof(DependencyParameterElement))]
10 [XmlElement("value", typeof(ValueParameterElement))]
11 [XmlElement("serialized", typeof(SerializedParameterElement))]
12 [XmlElement("default", typeof(DefaultParameterElement))]
13 [XmlElement("array", typeof(ArrayParameterElement))]
14 public AbstractInjectionParameter[] Parameters { get; set; }
15
16 public override void Visit(TypeRegistrationBuilder context) {
17 context.Visit(this);
18 }
19 }
20 } No newline at end of file
@@ -0,0 +1,15
1 using System.Xml.Serialization;
2
3 namespace Implab.ServiceHost.Unity
4 {
5 [XmlRoot("namespace", Namespace = Schema.ContainerConfigurationNamespace)]
6 public class NamespaceElement : AbstractContainerItem {
7
8 [XmlAttribute("name")]
9 public string Name { get; set; }
10
11 public override void Visit(ContainerBuilder builder) {
12 builder.AddNamespace(Name);
13 }
14 }
15 } No newline at end of file
@@ -0,0 +1,48
1 using System;
2 using System.Text;
3
4 namespace Implab.ServiceHost.Unity {
5 public class NestedTypeReference : TypeReference {
6
7 readonly string m_name;
8
9 readonly int m_genericParametersCount;
10
11 public TypeReference DeclaringType { get; private set; }
12
13 public override string Name {
14 get {
15 return m_name;
16 }
17 }
18
19 public override string Namespace {
20 get {
21 return DeclaringType.Namespace;
22 }
23 }
24
25 public override int GenericParametersCount {
26 get {
27 return m_genericParametersCount;
28 }
29 }
30
31 internal NestedTypeReference(TypeReference declaringType, string name, int parametersCount) {
32 DeclaringType = declaringType;
33 m_name = name;
34 m_genericParametersCount = parametersCount;
35 }
36
37 internal override void Visit(TypeResolutionContext visitor) {
38 visitor.Visit(this);
39 }
40
41 internal override void WriteTypeName(StringBuilder builder) {
42 builder
43 .Append(DeclaringType)
44 .Append('+')
45 .Append(Name);
46 }
47 }
48 } No newline at end of file
@@ -0,0 +1,20
1 using System.Xml.Serialization;
2
3 namespace Implab.ServiceHost.Unity {
4 public class PropertyInjectionElement : AbstractMemberInjection {
5
6 [XmlAttribute("name")]
7 public string Name { get; set; }
8
9 [XmlElement("dependency", typeof(DependencyParameterElement))]
10 [XmlElement("value", typeof(ValueParameterElement))]
11 [XmlElement("serialized", typeof(SerializedParameterElement))]
12 [XmlElement("default", typeof(DefaultParameterElement))]
13 [XmlElement("array", typeof(ArrayParameterElement))]
14 public AbstractInjectionParameter Value { get; set; }
15
16 public override void Visit(TypeRegistrationBuilder context) {
17 context.Visit(this);
18 }
19 }
20 } No newline at end of file
@@ -0,0 +1,17
1 using System.Xml.Serialization;
2
3 namespace Implab.ServiceHost.Unity {
4 public class ProvidesElement {
5 [XmlAttribute("type")]
6 public string RegistrationType { get; set; }
7
8 [XmlAttribute("name")]
9 public string RegistrationName { get; set; }
10
11 [XmlElement("signleton", typeof(SingletonLifetimeElement))]
12 [XmlElement("context", typeof(ContextLifetimeElement))]
13 [XmlElement("container", typeof(ContainerLifetimeElement))]
14 [XmlElement("hierarchy", typeof(HierarchicalLifetimeElement))]
15 public LifetimeElement Lifetime {get; set;}
16 }
17 } No newline at end of file
@@ -0,0 +1,39
1 using System;
2 using System.Collections.Generic;
3 using System.Xml.Serialization;
4 using Unity.Lifetime;
5 using Unity.Registration;
6
7 namespace Implab.ServiceHost.Unity {
8
9 [XmlRoot("register", Namespace = Schema.ContainerConfigurationNamespace)]
10 public class RegisterElement : AbstractRegistration, ITypeRegistration {
11
12 /// <summary>
13 /// An optional type which is registered as a service in the container, must be assignable to <see cref="ProvidesType">.
14 /// </summary>
15 [XmlAttribute("mapTo")]
16 public string MapToType { get; set; }
17
18
19 [XmlElement("constructor", typeof(ConstructorInjectionElement))]
20 [XmlElement("property", typeof(PropertyInjectionElement))]
21 [XmlElement("method", typeof(MethodInjectionElement))]
22 public AbstractMemberInjection[] Injectors { get; set; }
23
24 IEnumerable<ITypeMemberInjection> ITypeRegistration.MemberInjections {
25 get {
26 return Injectors;
27 }
28 }
29
30 public Type GetImplementationType(ContainerBuilder builder) {
31 return builder.ResolveType(MapToType);
32 }
33
34 public override void Visit(ContainerBuilder builder) {
35 builder.Visit(this);
36 }
37 }
38
39 } No newline at end of file
@@ -0,0 +1,32
1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Linq;
5 using System.Xml.Serialization;
6 using Implab.Xml;
7 using Unity.Injection;
8 using Unity.Lifetime;
9 using Unity.Registration;
10
11 namespace Implab.ServiceHost.Unity {
12 /// <summary>
13 /// Базовый класс для формирования записей в контейнере, созволяет указать время жизни для записи
14 /// </summary>
15 public abstract class RegistrationBuilder {
16 public ContainerBuilder Root {
17 get; private set;
18 }
19
20 public Type RegistrationType {
21 get;
22 private set;
23 }
24
25 internal LifetimeManager Lifetime { get; set; }
26
27 protected RegistrationBuilder(Type registrationType, ContainerBuilder root) {
28 Root = root;
29 RegistrationType = registrationType;
30 }
31 }
32 } No newline at end of file
@@ -0,0 +1,36
1 using System;
2
3 namespace Implab.ServiceHost.Unity
4 {
5 public class RootTypeReference : TypeReference {
6 readonly string m_name;
7
8 readonly string m_namespace;
9
10 readonly int m_genericParametersCount;
11
12 public override string Name {
13 get { return m_name; }
14 }
15
16 public override string Namespace {
17 get { return m_namespace; }
18 }
19
20 public override int GenericParametersCount {
21 get { return m_genericParametersCount; }
22 }
23
24 internal RootTypeReference(string ns, string name, int genericParameters) {
25 m_name = name;
26 m_genericParametersCount = genericParameters;
27 m_namespace = ns;
28 }
29
30 internal override void Visit(TypeResolutionContext visitor) {
31 visitor.Visit(this);
32 }
33
34
35 }
36 } No newline at end of file
@@ -0,0 +1,5
1 namespace Implab.ServiceHost.Unity {
2 public static class Schema {
3 public const string ContainerConfigurationNamespace = "http://implab.org/schemas/servicehost/unity.v1.xsd";
4 }
5 } No newline at end of file
@@ -0,0 +1,32
1 using System;
2 using System.Collections.Generic;
3 using System.Xml;
4 using System.Xml.Serialization;
5
6 namespace Implab.ServiceHost.Unity {
7 public class SerializedElement : AbstractRegistration, IInstanceRegistration {
8 [XmlAttribute("href")]
9 public string Location { get; set; }
10
11 [XmlAttribute("serializedType")]
12 public string SerializedType { get; set; }
13
14
15 [XmlAnyElement]
16 public XmlElement[] Content { get; set; }
17
18 public IEnumerable<IInjectionParameter> MemberInjections {
19 get {
20 yield return new SerializedParameterElement {
21 TypeName = SerializedType,
22 Location = Location,
23 Content = Content
24 };
25 }
26 }
27
28 public override void Visit(ContainerBuilder builder) {
29 builder.Visit(this);
30 }
31 }
32 } No newline at end of file
@@ -0,0 +1,33
1 using System;
2 using System.Xml;
3 using System.Xml.Schema;
4 using System.Xml.Serialization;
5
6 namespace Implab.ServiceHost.Unity
7 {
8 public class SerializedParameterElement : AbstractInjectionParameter {
9 [XmlAttribute("href")]
10 public string Location { get; set; }
11
12 [XmlAnyElement]
13 public XmlElement[] Content { get; set; }
14
15 public XmlReader GetReader(InjectionParameterBuilder builder) {
16 if (!string.IsNullOrEmpty(Location))
17 return XmlReader.Create(builder.Root.MakeLocationUri(Location).ToString());
18 if (Content != null && Content.Length > 0)
19 return Content[0].CreateNavigator().ReadSubtree();
20
21 throw new Exception("No content found, expected XML document");
22 }
23
24 public override void Visit(InjectionParameterBuilder builder) {
25 var type = builder.ResolveInjectedValueType(TypeName);
26
27 var serializer = new XmlSerializer(type);
28 using(var reader = GetReader(builder))
29 builder.SetValue(type, serializer.Deserialize(reader));
30
31 }
32 }
33 } No newline at end of file
@@ -0,0 +1,10
1 using Unity.Lifetime;
2
3 namespace Implab.ServiceHost.Unity
4 {
5 public class SingletonLifetimeElement : LifetimeElement {
6 public override LifetimeManager GetLifetime(ContainerBuilder builder) {
7 return new SingletonLifetimeManager();
8 }
9 }
10 } No newline at end of file
@@ -0,0 +1,52
1 using System;
2 using System.Linq;
3 using System.Text;
4
5 namespace Implab.ServiceHost.Unity {
6 public class SpecializedTypeReference : TypeReference {
7 public override string Name {
8 get {
9 return GenericType.Name;
10 }
11 }
12
13 public override string Namespace {
14 get {
15 return GenericType.Namespace;
16 }
17 }
18
19 public override int GenericParametersCount {
20 get {
21 return GenericParameters.Length;
22 }
23 }
24
25 public TypeReference GenericType { get; private set; }
26
27 public TypeReference[] GenericParameters { get; private set; }
28
29 internal SpecializedTypeReference(TypeReference genericType, TypeReference[] genericParameters) {
30 GenericType = genericType;
31 GenericParameters = genericParameters;
32 }
33
34 internal override void Visit(TypeResolutionContext visitor) {
35 visitor.Visit(this);
36 }
37
38 internal override void WriteTypeName(StringBuilder builder) {
39 GenericType.WriteTypeName(builder);
40 }
41
42 internal override void WriteTypeParams(StringBuilder builder) {
43 builder.Append('{');
44 for (var i = 0; i < GenericParameters.Length; i++) {
45 if (i > 0)
46 builder.Append(',');
47 builder.Append(GenericParameters[i]);
48 }
49 builder.Append('}');
50 }
51 }
52 } No newline at end of file
@@ -0,0 +1,182
1 using System;
2 using System.Linq;
3 using System.Text;
4
5 namespace Implab.ServiceHost.Unity {
6 /// <summary>
7 /// Ссылка на тип, является абстрактной записью имени CLR типа.
8 /// </summary>
9 /// <remarks>
10 /// Ссылка на тип содержит сокращенную информацию о типе и для ее интерпретации
11 /// требуется некоторый контекст, который позволит превратить ее в полноценный
12 /// <see cref="Type"/>. Ссылки на тип позволяют записать:
13 /// <list>
14 /// <item><description>общие типы, их специализации</description></item>
15 /// <item><description>вложенные типы</description></item>
16 /// <item><description>массивы</description></item>
17 /// </list>
18 /// <para>
19 /// Для получения из ссылки на тип конкретного CLR типа используется <see cref="TypeResolver.Resolve(TypeReference, bool)"/>.
20 /// </para>
21 /// <para>
22 /// Ссылку на тип можно создать либо програмно при помощи методов <see cref="Create(string, string, int)"/>,
23 /// <see cref="Create(string, int)"/>, <see cref="MakeArrayType(int)"/>, <see cref="MakeGenericType(TypeReference[])"/>,
24 /// либо разобрав строку со спецификацией при помощи метода <see cref="Parse(string)"/>.
25 /// </para>
26 /// <para>
27 /// Спецификация ссыдки на тип имеет следующий вид <c>Name.Space.MyType+Nested{String}[][]</c>, где:
28 /// <list type="table">
29 /// <item>
30 /// <term><c>.</c></term>
31 /// <description>Разделяет элементы пространства имен</description>
32 /// <item>
33 /// <item>
34 /// <term><c>+</c></term>
35 /// <description>Разделяет вложенные типы</description>
36 /// <item>
37 /// <item>
38 /// <term><c>[]</c>, <c>[,,,]</c></term>
39 /// <description>Указывает на то, что тип является массивом, также указывается его размерность</description>
40 /// <item>
41 /// <item>
42 /// <term><c>{}</c>, <c>{,,}</c>, <c>{Int32,String}</c></term>
43 /// <description>Указывает на то, что тип является общим, также
44 /// указывается количество параметров, либо конкретные типы для
45 /// специализации</description>
46 /// <item>
47 /// </list>
48 /// </para>
49 /// </remarks>
50 public abstract class TypeReference {
51
52 /// <summary>
53 /// Имя типа без дополнительных элементов, указывающих на то, что он общий или массив.
54 /// </summary>
55 /// <remarks>
56 /// Для массивов это имя его элементов.
57 /// </remarks>
58 public abstract string Name { get; }
59
60 /// <summary>
61 /// Пространство имен в котором нахожится тип.
62 /// </summary>
63 /// <remarks>
64 /// Для вложенных типов это пространтство имен типа самого верхнего уровня,
65 /// для массивов - пространство имен его элементов.
66 /// </remarks>
67 public abstract string Namespace { get; }
68
69 /// <summary>
70 /// Количество параметров общего типа.
71 /// </summary>
72 /// <remarks>
73 /// <para>
74 /// Вложенные типы неявно получают параметры от типов в которых они объявлены,
75 /// данное свойство это не учитывает, возвращается только количество собственных
76 /// параметров.
77 /// </para>
78 /// <para>
79 /// Данное свойство используется для получения CRL имени типа.
80 /// </para>
81 /// </remarks>
82 public abstract int GenericParametersCount { get; }
83
84 public virtual string ClrName {
85 get {
86 return GenericParametersCount != 0 ? $"{Name}`{GenericParametersCount}" : Name;
87 }
88 }
89
90 /// <summary>
91 /// Создает ссылку на специализацию текущего типа.
92 /// </summary>
93 /// <param name="genericParameters">Ссылки на типы, которые будут использоваться для специализации текущего типа.</param>
94 /// <returns>Специализация данного типа.</returns>
95 public virtual SpecializedTypeReference MakeGenericType(TypeReference[] genericParameters) {
96 if (GenericParametersCount == 0)
97 throw new InvalidOperationException("Can't specialize a non-geneic type");
98
99 if (genericParameters == null || GenericParametersCount != genericParameters.Length)
100 throw new InvalidOperationException("Generic parameters count mismatch");
101
102 return new SpecializedTypeReference(this, genericParameters);
103 }
104
105 /// <summary>
106 /// Создает ссылку на тип массива указанной размерности, элементами которого являются экземпаляры даннго типа.
107 /// </summary>
108 /// <param name="rank">Размерность, если размерность <c>1</c> создается вектор (<see cref="Type.MakeArrayType()"/>).</param>
109 /// <returns>Ссылка на тип массива</returns>
110 public ArrayTypeReference MakeArrayType(int rank) {
111 Safe.ArgumentInRange(rank > 0, nameof(rank));
112
113 return new ArrayTypeReference(this, rank);
114 }
115
116 /// <summary>
117 /// Создает ссылку на вложенный тип.
118 /// </summary>
119 /// <param name="name">Имя типа</param>
120 /// <param name="genericParameters">Количество параметров, если это общий тип, иначе 0.</param>
121 /// <returns>Ссылка на вложенный тип.</returns>
122 public TypeReference Create(string name, int genericParameters) {
123 Safe.ArgumentNotEmpty(name, nameof(name));
124 Safe.ArgumentInRange(genericParameters >= 0, nameof(genericParameters));
125
126 return new NestedTypeReference(this, name, genericParameters);
127 }
128
129 /// <summary>
130 /// Возвращает строковое представление ссылки на тип.
131 /// </summary>
132 /// <returns></returns>
133 public override string ToString() {
134 var builder = new StringBuilder();
135 WriteTypeName(builder);
136 WriteTypeParams(builder);
137 return builder.ToString();
138 }
139
140 internal virtual void WriteTypeName(StringBuilder builder) {
141 if (!string.IsNullOrEmpty(Namespace))
142 builder
143 .Append(Namespace)
144 .Append('.');
145 builder.Append(Name);
146 }
147
148 internal virtual void WriteTypeParams(StringBuilder builder) {
149 if (GenericParametersCount > 0)
150 builder
151 .Append('{')
152 .Append(',', GenericParametersCount-1)
153 .Append('}');
154 }
155
156 internal abstract void Visit(TypeResolutionContext visitor);
157
158 /// <summary>
159 /// Создает ссылку на тип.
160 /// </summary>
161 /// <param name="ns">Пространство имен, либо его фрагмент.</param>
162 /// <param name="name">Имя типа без указания на количество параметров, либо на то, что это массив.</param>
163 /// <param name="genericParameters">Количество параметров типа, если это общий тип, иначе 0.</param>
164 /// <returns>Ссылка на тип.</returns>
165 public static TypeReference Create(string ns, string name, int genericParameters) {
166 Safe.ArgumentNotEmpty(name, nameof(name));
167 Safe.ArgumentInRange(genericParameters >= 0, nameof(genericParameters));
168 return new RootTypeReference(ns, name, genericParameters);
169 }
170
171 /// <summary>
172 /// Разирает строковую запись ссылки на тип.
173 /// </summary>
174 /// <param name="typeSpec">Строковая запись ссылки на тип, например <c>Dictionary{String,String}</c></param>
175 /// <returns>Ссылка на тип.</returns>
176 public static TypeReference Parse(string typeSpec) {
177 var parser = new TypeReferenceParser(typeSpec);
178 return parser.Parse();
179 }
180
181 }
182 } No newline at end of file
@@ -0,0 +1,245
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text.RegularExpressions;
5
6 namespace Implab.ServiceHost.Unity {
7 internal class TypeReferenceParser {
8 enum TokenType {
9 None,
10
11 Word,
12
13 Dot,
14
15 Comma,
16
17 OpenList,
18
19 CloseList,
20
21 OpenArray,
22
23 CloseArray,
24
25 Plus,
26
27 Eof
28 }
29
30 readonly Regex _tokens = new Regex(@"\G(?:([\w]+)|\s*([\+\.{},\[\]])\s*)", RegexOptions.Compiled);
31
32 TokenType m_token;
33
34 string m_tokenValue;
35
36 int m_pos;
37
38 int m_tokenPos;
39
40 readonly string m_text;
41
42 TokenType Token { get { return m_token; } }
43
44 string TokenValue { get { return m_tokenValue; } }
45
46 int TokenPos { get { return m_tokenPos; } }
47
48 public TypeReferenceParser(string text) {
49 Safe.ArgumentNotEmpty(text, nameof(text));
50 m_text = text;
51 }
52
53 bool ReadToken() {
54 if (m_pos >= m_text.Length) {
55 m_token = TokenType.Eof;
56 m_tokenValue = null;
57 return false;
58 }
59
60 var m = _tokens.Match(m_text, m_pos);
61
62 if (m.Success) {
63 m_tokenPos = m_pos;
64 m_pos += m.Length;
65 if (m.Groups[1].Success) {
66 m_token = TokenType.Word;
67 m_tokenValue = m.Groups[1].Value;
68 } else if (m.Groups[2].Success) {
69 m_tokenValue = null;
70 switch (m.Groups[2].Value) {
71 case "{":
72 m_token = TokenType.OpenList;
73 break;
74 case "}":
75 m_token = TokenType.CloseList;
76 break;
77 case ".":
78 m_token = TokenType.Dot;
79 break;
80 case ",":
81 m_token = TokenType.Comma;
82 break;
83 case "[":
84 m_token = TokenType.OpenArray;
85 break;
86 case "]":
87 m_token = TokenType.CloseArray;
88 break;
89 case "+":
90 m_token = TokenType.Plus;
91 break;
92 }
93 }
94 return true;
95 }
96 throw new FormatException($"Failed to parse '{m_text}' at pos {m_pos}");
97 }
98
99 public TypeReference Parse() {
100 var result = ReadTypeReference();
101 if (Token != TokenType.Eof)
102 ThrowUnexpectedToken();
103 return result;
104 }
105
106 string[] ReadQTypeName() {
107 var parts = new List<string>();
108
109 string current = null;
110 bool stop = false;
111 while ((!stop) && ReadToken()) {
112 switch (Token) {
113 case TokenType.Word:
114 if (current != null)
115 ThrowUnexpectedToken();
116 current = TokenValue;
117 break;
118 case TokenType.Dot:
119 if (current == null)
120 ThrowUnexpectedToken();
121 parts.Add(current);
122 current = null;
123 break;
124 default:
125 stop = true;
126 break;
127 }
128 }
129 if (current != null)
130 parts.Add(current);
131
132 if (parts.Count == 0)
133 return null;
134
135 return parts.ToArray();
136 }
137
138 string ReadNQTypeName() {
139 ReadToken();
140 if (Token != TokenType.Word)
141 ThrowUnexpectedToken();
142 return TokenValue;
143 }
144
145 TypeReference ReadTypeReference() {
146
147 var parts = ReadQTypeName();
148 if (parts == null)
149 return null;
150
151 var genericParameters = ReadGenericParams();
152
153 var typeReference = TypeReference.Create(
154 string.Join(".", parts, 0, parts.Length - 1),
155 parts[parts.Length - 1],
156 genericParameters.Length
157 );
158
159 if (genericParameters.Length > 0 && genericParameters.All(x => x != null))
160 typeReference = typeReference.MakeGenericType(genericParameters);
161
162 typeReference = ReadArraySpec(typeReference);
163
164 if(Token == TokenType.Plus)
165 return ReadNestedType(typeReference);
166
167 return typeReference;
168 }
169
170 TypeReference ReadNestedType(TypeReference declaringType) {
171 var name = ReadNQTypeName();
172 if(string.IsNullOrEmpty(name))
173 throw new FormatException("Nested type name can't be empty");
174 ReadToken();
175
176 var genericParameters = ReadGenericParams();
177
178 var typeReference = declaringType.Create(
179 name,
180 genericParameters.Length
181 );
182
183 if (genericParameters.Length > 0 && genericParameters.All(x => x != null))
184 typeReference = typeReference.MakeGenericType(genericParameters);
185
186 typeReference = ReadArraySpec(typeReference);
187
188 if(Token == TokenType.Plus)
189 return ReadNestedType(typeReference);
190
191 return typeReference;
192 }
193
194 TypeReference[] ReadGenericParams() {
195 if (Token == TokenType.OpenList) {
196 var genericParameters = ReadTypeReferenceList();
197 if (Token != TokenType.CloseList)
198 ThrowUnexpectedToken();
199 ReadToken();
200
201 return genericParameters;
202 }
203
204 return Array.Empty<TypeReference>();
205 }
206
207 TypeReference ReadArraySpec(TypeReference typeReference) {
208 while (Token == TokenType.OpenArray) {
209 var rank = CountRank();
210 if (Token != TokenType.CloseArray)
211 ThrowUnexpectedToken();
212
213 typeReference = typeReference.MakeArrayType(rank);
214
215 ReadToken();
216 }
217
218 return typeReference;
219 }
220
221 int CountRank() {
222 int rank = 0;
223 do {
224 rank++;
225 } while(ReadToken() && Token == TokenType.Comma);
226 return rank;
227 }
228
229 TypeReference[] ReadTypeReferenceList() {
230 var list = new List<TypeReference>();
231
232 do {
233 var typeReference = ReadTypeReference();
234 list.Add(typeReference);
235 } while (Token == TokenType.Comma);
236
237 return list.ToArray();
238 }
239
240 void ThrowUnexpectedToken() {
241 throw new FormatException($"Unexpected '{Token}' at pos {TokenPos}: -->{m_text.Substring(TokenPos, Math.Min(m_text.Length - TokenPos, 10))}");
242 }
243
244 }
245 } No newline at end of file
@@ -0,0 +1,81
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using Unity.Injection;
5 using Unity.Registration;
6
7 namespace Implab.ServiceHost.Unity {
8 public class TypeRegistrationBuilder : RegistrationBuilder {
9
10 readonly TypeResolver m_resolver;
11
12 readonly List<InjectionMember> m_injections = new List<InjectionMember>();
13
14 internal InjectionMember[] Injections { get { return m_injections.ToArray(); } }
15
16 public Type ImplementationType {
17 get;
18 private set;
19 }
20
21 internal TypeRegistrationBuilder(TypeResolver resolver, Type registrationType, Type implementationType, ContainerBuilder root) : base(registrationType, root) {
22 ImplementationType = implementationType;
23
24 // when registering a generic mapping, register all generic parameter names as local types
25 if (ImplementationType.IsGenericTypeDefinition) {
26 m_resolver = new TypeResolver(resolver);
27
28 foreach (var p in ImplementationType.GetGenericArguments())
29 m_resolver.AddMapping(p.Name, p);
30 } else {
31 m_resolver = resolver;
32 }
33 }
34
35 internal void Visit(ConstructorInjectionElement constructorInjection) {
36
37
38 var parameters = constructorInjection.Parameters?
39 .Select(x => {
40 var valueBuilder = new InjectionParameterBuilder(m_resolver, null, Root);
41 x.Visit(valueBuilder);
42 return valueBuilder.Injection;
43 })
44 .ToArray();
45
46 var injection = parameters != null ? new InjectionConstructor(parameters) : new InjectionConstructor();
47 m_injections.Add(injection);
48 }
49
50 internal void Visit(MethodInjectionElement methodInjection) {
51 var parameters = methodInjection.Parameters?
52 .Select(x => {
53 var valueBuilder = new InjectionParameterBuilder(m_resolver, null, Root);
54 x.Visit(valueBuilder);
55 return valueBuilder.Injection;
56 })
57 .ToArray();
58
59 var injection = parameters != null ? new InjectionMethod(methodInjection.Name, parameters) : new InjectionMethod(methodInjection.Name);
60 m_injections.Add(injection);
61 }
62
63 internal void Visit(PropertyInjectionElement propertyInjection) {
64 if (propertyInjection.Value == null)
65 throw new Exception($"A value value must be specified for the property '{propertyInjection.Name}'");
66
67 var propertyType = ImplementationType.GetProperty(propertyInjection.Name)?.PropertyType;
68 var valueContext = new InjectionParameterBuilder(m_resolver, propertyType, Root);
69
70 propertyInjection.Value.Visit(valueContext);
71 var injection = new InjectionProperty(propertyInjection.Name, valueContext.Injection);
72 m_injections.Add(injection);
73 }
74
75 public void AddInjectionMember(InjectionMember injection) {
76 Safe.ArgumentNotNull(injection, nameof(injection));
77
78 m_injections.Add(injection);
79 }
80 }
81 } No newline at end of file
@@ -0,0 +1,75
1 using System;
2 using System.Collections.Generic;
3 using Implab.Diagnostics;
4
5 namespace Implab.ServiceHost.Unity {
6 using static Trace<TypeResolver>;
7
8 /// <summary>
9 /// Позволяет обойти вложенные типы и собрать цеочку из типов и параметров генериков, которые они предлагают
10 /// </summary>
11 internal class TypeResolutionContext {
12 readonly TypeResolver m_resolver;
13
14
15 readonly List<Type> m_genericParameters = new List<Type>();
16
17 public IEnumerable<Type> GenericParameters { get { return m_genericParameters; } }
18
19 public Type ResolvedType { get; private set; }
20
21
22 public int ArrayRank { get; private set; }
23
24
25 public bool ThrowOnFail { get; private set; }
26
27 public TypeResolutionContext(TypeResolver resolver, bool throwOnFail) {
28 m_resolver = resolver;
29 ThrowOnFail = throwOnFail;
30 }
31
32 public Type MakeType() {
33 return m_genericParameters.Count > 0 ?
34 ResolvedType?.MakeGenericType(m_genericParameters.ToArray()) :
35 ResolvedType;
36 }
37
38 public void Visit(SpecializedTypeReference typeReference) {
39 typeReference.GenericType.Visit(this);
40
41 if (ResolvedType != null) {
42 foreach (var genericParamRef in typeReference.GenericParameters) {
43 var context = new TypeResolutionContext(m_resolver, ThrowOnFail);
44 genericParamRef.Visit(context);
45 m_genericParameters.Add(context.MakeType());
46 }
47 }
48 }
49
50 public void Visit(NestedTypeReference typeReference) {
51 typeReference.DeclaringType.Visit(this);
52 if (ResolvedType != null)
53 ResolvedType = ResolvedType?.GetNestedType(typeReference.ClrName) ?? Failed(typeReference);
54 }
55
56 public void Visit(RootTypeReference typeReference) {
57 ResolvedType = m_resolver.Resolve(typeReference.Namespace, typeReference.ClrName) ?? Failed(typeReference);
58 }
59
60 public void Visit(ArrayTypeReference typeReference) {
61 var context = new TypeResolutionContext(m_resolver, ThrowOnFail);
62 typeReference.ItemsType.Visit(context);
63 ResolvedType = typeReference.Rank == 1 ?
64 context.MakeType()?.MakeArrayType() :
65 context.MakeType()?.MakeArrayType(typeReference.Rank);
66 }
67
68 Type Failed(TypeReference reference) {
69 Log($"Falied to resolve {reference}");
70 if (ThrowOnFail)
71 throw new Exception($"Failed to resolve {reference}");
72 return null;
73 }
74 }
75 } No newline at end of file
@@ -0,0 +1,99
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Text.RegularExpressions;
6 using Implab.Diagnostics;
7
8 namespace Implab.ServiceHost.Unity {
9 using System.Diagnostics;
10 using static Trace<TypeResolver>;
11 public class TypeResolver {
12 readonly Dictionary<string, Type> m_cache = new Dictionary<string, Type>();
13
14 Regex _nsRx = new Regex(@"^\w+(\.\w+)*$", RegexOptions.Compiled);
15 readonly LinkedList<string> m_namespases = new LinkedList<string>();
16
17 internal Type Resolve(string ns, string typeName) {
18 var fullName = string.IsNullOrEmpty(ns) ? typeName : $"{ns}.{typeName}";
19
20 return ProbeInNamespaces(fullName);
21 }
22
23 public Type Resolve(TypeReference typeReference, bool throwOnFail) {
24 var context = new TypeResolutionContext(this, throwOnFail);
25 typeReference.Visit(context);
26 return context.MakeType();
27 }
28
29 public Type Resolve(string typeSpec, bool throwOnFail) {
30 Safe.ArgumentNotEmpty(typeSpec, nameof(typeSpec));
31 var typeReference = TypeReference.Parse(typeSpec);
32 return Resolve(typeReference, throwOnFail);
33 }
34
35 LinkedListNode<string> m_insertAt;
36
37 readonly TypeResolver m_parent;
38
39 public TypeResolver() : this(null) {
40 }
41
42 public TypeResolver(TypeResolver parent) {
43 m_parent = parent;
44 m_insertAt = new LinkedListNode<string>(string.Empty);
45 m_namespases.AddFirst(m_insertAt);
46 }
47
48 public void AddNamespace(string ns) {
49 Safe.ArgumentMatch(ns, nameof(ns), _nsRx);
50 if (m_insertAt != null)
51 m_namespases.AddAfter(m_insertAt, ns);
52 else
53 m_namespases.AddFirst(ns);
54 }
55
56 public void AddMapping(string typeName, Type type) {
57 Safe.ArgumentNotEmpty(typeName, nameof(typeName));
58 Safe.ArgumentNotNull(type, nameof(type));
59
60 m_cache[typeName] = type;
61 }
62
63 Type ProbeInNamespaces(string localName) {
64
65 Type resolved;
66 if (!m_cache.TryGetValue(localName, out resolved)) {
67 foreach (var ns in m_namespases) {
68 var typeName = string.IsNullOrEmpty(ns) ? localName : $"{ns}.{localName}";
69 resolved = Probe(typeName);
70 if (resolved != null) {
71 Log($"Probe '{localName}' -> '{resolved.FullName}'");
72 break;
73 }
74 }
75
76 if (resolved == null && m_parent != null)
77 resolved = m_parent.ProbeInNamespaces(localName);
78
79 if(resolved == null)
80 Log($"Probe '{localName}' failed");
81
82 m_cache[localName] = resolved;
83 }
84
85 return resolved;
86 }
87
88 Type Probe(string typeName) {
89 var assemblies = AppDomain.CurrentDomain.GetAssemblies();
90
91 foreach (var assembly in assemblies) {
92 var type = assembly.GetType(typeName);
93 if (type != null)
94 return type;
95 }
96 return null;
97 }
98 }
99 } No newline at end of file
@@ -0,0 +1,40
1 using System.IO;
2 using Unity;
3
4 namespace Implab.ServiceHost.Unity
5 {
6 public static class UnityContainerExtensions
7 {
8 public static IUnityContainer LoadXmlConfiguration(this IUnityContainer container, string file, ContainerConfigurationSchema schema) {
9 Safe.ArgumentNotNull(container, nameof(container));
10 var builder = new ContainerBuilder(container,schema);
11 builder.LoadConfig(file);
12 return builder.Container;
13 }
14
15 public static IUnityContainer LoadXmlConfiguration(this IUnityContainer container, Stream stream, ContainerConfigurationSchema schema) {
16 Safe.ArgumentNotNull(container, nameof(container));
17 Safe.ArgumentNotNull(stream, nameof(stream));
18
19 if (schema == null)
20 schema = ContainerConfigurationSchema.Default;
21
22 var builder = new ContainerBuilder(container,schema);
23 var config = (ContainerElement)schema.Serializer.Deserialize(stream);
24 if (config.Items != null) {
25 foreach(var item in config.Items)
26 item?.Visit(builder);
27 }
28
29 return builder.Container;
30 }
31
32 public static IUnityContainer LoadXmlConfiguration(this IUnityContainer container, Stream stream) {
33 return LoadXmlConfiguration(container, stream, ContainerConfigurationSchema.Default);
34 }
35
36 public static IUnityContainer LoadXmlConfiguration(this IUnityContainer container, string file) {
37 return LoadXmlConfiguration(container, file, ContainerConfigurationSchema.Default);
38 }
39 }
40 } No newline at end of file
@@ -0,0 +1,36
1 using System.Collections.Generic;
2 using System.Xml.Serialization;
3
4 namespace Implab.ServiceHost.Unity {
5 public class ValueElement : AbstractRegistration, IInstanceRegistration {
6
7 [XmlAttribute("value")]
8 public string Value { get; set; }
9
10 [XmlText]
11 public string Text { get; set; }
12
13 string GetTextValue() {
14 return string.IsNullOrEmpty(Value) ? Text : Value;
15 }
16
17 public string TypeName {
18 get {
19 return RegistrationType;
20 }
21 }
22
23 public IEnumerable<IInjectionParameter> MemberInjections {
24 get {
25 yield return new ValueParameterElement {
26 Value = Value,
27 Text = Text
28 };
29 }
30 }
31
32 public override void Visit(ContainerBuilder builder) {
33 builder.Visit(this);
34 }
35 }
36 } No newline at end of file
@@ -0,0 +1,21
1 using System.ComponentModel;
2 using System.Xml.Serialization;
3
4 namespace Implab.ServiceHost.Unity {
5 public class ValueParameterElement : AbstractInjectionParameter {
6 [XmlAttribute("value")]
7 public string Value { get; set; }
8
9 [XmlText]
10 public string Text { get; set; }
11
12 string GetTextValue() {
13 return string.IsNullOrEmpty(Value) ? Text : Value;
14 }
15
16 public override void Visit(InjectionParameterBuilder builder) {
17 var type = builder.ResolveInjectedValueType(TypeName);
18 builder.SetValue(type, TypeDescriptor.GetConverter(type).ConvertFromString(GetTextValue()));
19 }
20 }
21 } No newline at end of file
@@ -0,0 +1,34
1 using System;
2 using System.Threading;
3 using System.Threading.Tasks;
4 using Implab.Components;
5 using Implab.Diagnostics;
6 using Xunit;
7
8 namespace Implab.Test {
9
10 public class DiagnosticsTest {
11 class Foo {}
12
13 [Fact]
14 public void TestRegistration() {
15 var channel = TraceSourceChannel<Foo>.Default;
16
17 Assert.Equal(typeof(Foo), channel.Id);
18 Assert.Equal(typeof(Foo).FullName, channel.Source.Name);
19
20 TraceSourceChannel found = null;
21 int visited = 0;
22
23 TraceRegistry.Global.Subscribe(x => {
24 visited++;
25 found = x as TraceSourceChannel;
26 });
27
28 Assert.Equal(1,visited);
29 Assert.Equal(channel, found);
30
31 }
32
33 }
34 } No newline at end of file
@@ -0,0 +1,37
1 using System;
2 using System.Threading;
3 using System.Threading.Tasks;
4 using Implab.Components;
5
6 namespace Implab.Test {
7 public class MockPollComponent : PollingComponent {
8
9 public Func<CancellationToken,Task> PollWorker { get; set;}
10
11 public Func<CancellationToken, Task> StartWorker { get; set; }
12
13 public Func<CancellationToken, Task> StopWorker { get; set; }
14
15 public MockPollComponent(bool initialized) : base(initialized) {
16 }
17
18 protected async override Task Poll(CancellationToken ct) {
19 if(PollWorker!= null)
20 await PollWorker.Invoke(ct);
21 }
22
23 protected async override Task StopInternalAsync(CancellationToken ct) {
24 await base.StopInternalAsync(ct);
25 if (StopWorker != null)
26 await StopWorker.Invoke(ct);
27 }
28
29 protected async override Task StartInternalAsync(CancellationToken ct) {
30 await base.StartInternalAsync(ct);
31 if (StartWorker != null)
32 await StartWorker.Invoke(ct);
33 }
34
35
36 }
37 } No newline at end of file
@@ -0,0 +1,20
1 using System.Xml.Serialization;
2
3 namespace Implab.Test.Model {
4
5 [XmlRoot(Namespace="urn:implab:test:model")]
6 public class Person {
7 public string FirstName { get; set; }
8
9 public string LastName { get; set; }
10
11 public int Age { get; set; }
12
13 [XmlIgnore]
14 public bool AgeSpecified { get; set; }
15
16
17 [XmlElement("Tag")]
18 public string[] Tags { get; set; }
19 }
20 } No newline at end of file
@@ -0,0 +1,264
1 using System;
2 using System.Threading;
3 using System.Threading.Tasks;
4 using Implab.Components;
5 using Xunit;
6
7 namespace Implab.Test {
8
9 public class RunnableComponentTests {
10 [Fact]
11 public async Task SimpleStartStop() {
12
13 using (var m = new MockPollComponent(true)) {
14 m.StartWorker = async (ct) => await Task.Yield();
15 m.StopWorker = async (ct) => await Task.Yield();
16
17 Assert.Equal(ExecutionState.Ready, m.State);
18 Assert.NotNull(m.Completion);
19
20 m.Start();
21 await m.Completion;
22 Assert.Equal(ExecutionState.Running, m.State);
23
24 m.Stop();
25 await m.Completion;
26 Assert.Equal(ExecutionState.Stopped, m.State);
27 }
28 }
29
30 [Fact]
31 public async Task SyncStart() {
32 using (var m = new MockPollComponent(true)) {
33 m.Start();
34 Assert.Equal(ExecutionState.Running, m.State);
35 await m.Completion;
36 }
37 }
38
39 [Fact]
40 public async Task AsyncStarting() {
41 using (var m = new MockPollComponent(true)) {
42 var signal = Safe.CreateTask();
43
44 m.StartWorker = async (ct) => await signal;
45 m.Start();
46
47 Assert.Equal(ExecutionState.Starting, m.State);
48 Assert.False(m.Completion.IsCompleted);
49
50 signal.Start();
51
52 await m.Completion;
53
54 Assert.Equal(ExecutionState.Running, m.State);
55 }
56 }
57
58 [Fact]
59 public async Task FailWhileStarting() {
60 using (var m = new MockPollComponent(true)) {
61 const string failMessage = "Fail me";
62 var signal = new Task(() => {
63 throw new Exception(failMessage);
64 });
65
66 m.StartWorker = async (ct) => await signal;
67 m.Start();
68
69 Assert.Equal(ExecutionState.Starting, m.State);
70 Assert.False(m.Completion.IsCompleted);
71
72 signal.Start();
73 try {
74 await m.Completion;
75 Assert.True(false);
76 } catch (Exception e) {
77 Assert.Equal(failMessage, e.Message);
78 }
79
80 Assert.Equal(ExecutionState.Failed, m.State);
81 }
82 }
83
84 [Fact]
85 public async Task SyncStop() {
86 using (var m = new MockPollComponent(true)) {
87 m.Start();
88 Assert.Equal(ExecutionState.Running, m.State);
89 m.Stop();
90 Assert.Equal(ExecutionState.Stopped, m.State);
91 await m.Completion;
92 }
93 }
94
95 [Fact]
96 public async Task AsyncStopping() {
97 using (var m = new MockPollComponent(true)) {
98 var signal = Safe.CreateTask();
99
100 m.StopWorker = async (ct) => await signal;
101
102 // Start
103 m.Start();
104 Assert.Equal(ExecutionState.Running, m.State);
105
106 // Stop
107 m.Stop();
108 Assert.Equal(ExecutionState.Stopping, m.State);
109 Assert.False(m.Completion.IsCompleted);
110 signal.Start();
111
112 await m.Completion;
113
114 Assert.Equal(ExecutionState.Stopped, m.State);
115 }
116 }
117
118 [Fact]
119 public async Task FailWhileStopping() {
120 using (var m = new MockPollComponent(true)) {
121 const string failMessage = "Fail me";
122 var signal = new Task(() => {
123 throw new Exception(failMessage);
124 });
125
126 m.StopWorker = async (ct) => await signal;
127
128 // Start
129 m.Start();
130 Assert.Equal(ExecutionState.Running, m.State);
131
132 // Stop
133 m.Stop();
134 Assert.Equal(ExecutionState.Stopping, m.State);
135 Assert.False(m.Completion.IsCompleted);
136
137 signal.Start();
138 try {
139 await m.Completion;
140 Assert.True(false);
141 } catch (Exception e) {
142 Assert.Equal(failMessage, e.Message);
143 }
144
145 Assert.Equal(ExecutionState.Failed, m.State);
146 }
147 }
148
149 [Fact]
150 public async Task ThrowOnInvalidTrasition() {
151 using (var m = new MockPollComponent(false)) {
152 var started = Safe.CreateTask();
153 var stopped = Safe.CreateTask();
154
155 m.StartWorker = async (ct) => await started;
156 m.StopWorker = async (ct) => await stopped;
157
158 Assert.Throws<InvalidOperationException>(() => m.Start());
159
160 // Initialize
161 m.Initialize();
162 await m.Completion;
163
164 // Start
165 m.Start();
166 Assert.Equal(ExecutionState.Starting, m.State);
167
168 // Check invalid transitions
169 Assert.Throws<InvalidOperationException>(() => m.Start());
170
171 // Component can be stopped before started
172 // m.Stop(CancellationToken.None);
173
174 // Running
175 started.Start();
176 await m.Completion;
177 Assert.Equal(ExecutionState.Running, m.State);
178
179
180 Assert.Throws<InvalidOperationException>(() => m.Start());
181
182 // Stop
183 m.Stop();
184
185 // Check invalid transitions
186 Assert.Throws<InvalidOperationException>(() => m.Start());
187 Assert.Throws<InvalidOperationException>(() => m.Stop());
188
189 // Stopped
190 stopped.Start();
191 await m.Completion;
192 Assert.Equal(ExecutionState.Stopped, m.State);
193
194 // Check invalid transitions
195 Assert.Throws<InvalidOperationException>(() => m.Start());
196 Assert.Throws<InvalidOperationException>(() => m.Stop());
197 }
198 }
199
200 [Fact]
201 public async Task CancelStart() {
202 using (var m = new MockPollComponent(true)) {
203 m.StartWorker = (ct) => Safe.CreateTask(ct);
204
205 m.Start();
206 var start = m.Completion;
207
208 Assert.Equal(ExecutionState.Starting, m.State);
209 m.Stop();
210 await m.Completion;
211 Assert.Equal(ExecutionState.Stopped, m.State);
212 Assert.True(start.IsCompleted);
213 Assert.True(start.IsCanceled);
214 }
215 }
216
217 [Fact]
218 public async Task AwaitWorker() {
219 using (var m = new MockPollComponent(true)) {
220 var worker = Safe.CreateTask();
221
222 m.PollWorker = (ct) => worker;
223
224 m.Start(CancellationToken.None);
225 await m.Completion;
226
227 Assert.Equal(ExecutionState.Running, m.State);
228
229 m.Stop(CancellationToken.None);
230 Assert.Equal(ExecutionState.Stopping, m.State);
231 worker.Start();
232 await m.Completion;
233 Assert.Equal(ExecutionState.Stopped, m.State);
234 }
235 }
236
237 [Fact]
238 public async Task CancelWorker() {
239 using (var m = new MockPollComponent(true)) {
240 var worker = Safe.CreateTask();
241
242 var started = Safe.CreateTask();
243
244 m.PollWorker = async (ct) => {
245 started.Start();
246 await worker;
247 ct.ThrowIfCancellationRequested();
248 };
249
250 m.Start(CancellationToken.None);
251 await m.Completion;
252 await started; // await for the poll worker to start
253
254 Assert.Equal(ExecutionState.Running, m.State);
255
256 m.Stop(CancellationToken.None);
257 Assert.Equal(ExecutionState.Stopping, m.State);
258 worker.Start();
259 await m.Completion;
260 Assert.Equal(ExecutionState.Stopped, m.State);
261 }
262 }
263 }
264 }
@@ -0,0 +1,17
1 <?xml version="1.0"?>
2 <package >
3 <metadata>
4 <id>Implab</id>
5 <version>$version$</version>
6 <title>$title$</title>
7 <authors>Implab team</authors>
8 <owners>Implab team</owners>
9 <projectUrl>https://implab.org/</projectUrl>
10 <!-- <iconUrl>http://ICON_URL_HERE_OR_DELETE_THIS_LINE</iconUrl> -->
11 <requireLicenseAcceptance>false</requireLicenseAcceptance>
12 <description>Common components for asynchronous applications, tracing, logging, json and xml traits.</description>
13 <releaseNotes>Added strong name.</releaseNotes>
14 <copyright>Copyright 2017</copyright>
15 <tags>async xml json</tags>
16 </metadata>
17 </package> No newline at end of file
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
@@ -0,0 +1,22
1 Copyright 2012-2018 Sergey Smirnov
2
3 Redistribution and use in source and binary forms, with or without
4 modification, are permitted provided that the following conditions are met:
5
6 1. Redistributions of source code must retain the above copyright notice, this
7 list of conditions and the following disclaimer.
8
9 2. Redistributions in binary form must reproduce the above copyright notice,
10 this list of conditions and the following disclaimer in the documentation
11 and/or other materials provided with the distribution.
12
13 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
17 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
21 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. No newline at end of file
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,20 +1,29
1 syntax: glob
1 syntax: glob
2 Implab.Test/bin/
2 Implab.Test/bin/
3 *.user
3 *.user
4 Implab.Test/obj/
4 Implab.Test/obj/
5 *.userprefs
5 *.userprefs
6 Implab/bin/
6 Implab/bin/
7 Implab/obj/
7 Implab/obj/
8 TestResults/
8 TestResults/
9 Implab.Fx/obj/
9 Implab.Fx/obj/
10 Implab.Fx/bin/
10 Implab.Fx/bin/
11 Implab.Fx.Test/bin/
11 Implab.Fx.Test/bin/
12 Implab.Fx.Test/obj/
12 Implab.Fx.Test/obj/
13 _ReSharper.Implab/
13 _ReSharper.Implab/
14 Implab.Diagnostics.Interactive/bin/
14 Implab.Diagnostics.Interactive/bin/
15 Implab.Diagnostics.Interactive/obj/
15 Implab.Diagnostics.Interactive/obj/
16 MonoPlay/bin/
16 MonoPlay/bin/
17 MonoPlay/obj/
17 MonoPlay/obj/
18 Implab.Test/Implab.Format.Test/bin/
18 Implab.Test/Implab.Format.Test/bin/
19 Implab.Test/Implab.Format.Test/obj/
19 Implab.Test/Implab.Format.Test/obj/
20 *.suo
20 *.suo
21 Implab.Format.Test/bin/
22 Implab.Format.Test/obj/
23 packages/
24 Implab.Playground/obj/
25 Implab.Playground/bin/
26 Implab.ServiceHost/bin/
27 Implab.ServiceHost/obj/
28 Implab.ServiceHost.Test/bin/
29 Implab.ServiceHost.Test/obj/
@@ -1,1 +1,6
1 f1da3afc3521e0e1631ac19e09690bc0a241841a release v2.1
1 f1da3afc3521e0e1631ac19e09690bc0a241841a release v2.1
2 34df34841225f14ec65f4a5f28585d32b55829ad v3.0.1-beta
3 547a2fc0d93ea5f867c778d7eeaa5888cc24fb9e v3.0.6
4 f1696cdc3d7a5a9e19569567722285926c5d61b0 v3.0.8
5 74e048cbaac8cdd5a0825b1fd8b47dd932a05ae8 v3.0.10
6 95896f882995c74202bded87392585d287b16e82 v3.0.14
@@ -1,84 +1,24
1 <?xml version="1.0" encoding="utf-8"?>
1 <Project Sdk="Microsoft.NET.Sdk">
2 <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2 <PropertyGroup Condition="'$(OSTYPE)'=='linux'">
3 <PropertyGroup>
3 <TargetFrameworks>netcoreapp2.0;net46</TargetFrameworks>
4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
4 <FrameworkPathOverride Condition="'$(TargetFramework)'=='net46'">/usr/lib/mono/4.5/</FrameworkPathOverride>
5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
6 <ProductVersion>8.0.30703</ProductVersion>
7 <SchemaVersion>2.0</SchemaVersion>
8 <ProjectGuid>{63F92C0C-61BF-48C0-A377-8D67C3C661D0}</ProjectGuid>
9 <OutputType>Library</OutputType>
10 <AppDesignerFolder>Properties</AppDesignerFolder>
11 <RootNamespace>Implab.Test</RootNamespace>
12 <AssemblyName>Implab.Test</AssemblyName>
13 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
14 <FileAlignment>512</FileAlignment>
15 <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
16 <TargetFrameworkProfile />
17 </PropertyGroup>
5 </PropertyGroup>
18 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
6
19 <DebugSymbols>true</DebugSymbols>
7 <PropertyGroup Condition="'$(OSTYPE)'=='windows'">
20 <DebugType>full</DebugType>
8 <TargetFrameworks>netcoreapp2.0;net46</TargetFrameworks>
21 <Optimize>false</Optimize>
22 <OutputPath>bin\Debug\</OutputPath>
23 <DefineConstants>DEBUG;TRACE</DefineConstants>
24 <ErrorReport>prompt</ErrorReport>
25 <WarningLevel>4</WarningLevel>
26 <Prefer32Bit>false</Prefer32Bit>
27 </PropertyGroup>
28 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
29 <DebugType>pdbonly</DebugType>
30 <Optimize>true</Optimize>
31 <OutputPath>bin\Release\</OutputPath>
32 <DefineConstants>TRACE</DefineConstants>
33 <ErrorReport>prompt</ErrorReport>
34 <WarningLevel>4</WarningLevel>
35 <Prefer32Bit>false</Prefer32Bit>
36 </PropertyGroup>
9 </PropertyGroup>
37 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' ">
10
38 <DebugSymbols>true</DebugSymbols>
11 <PropertyGroup>
39 <DebugType>full</DebugType>
12 <IsPackable>false</IsPackable>
40 <Optimize>false</Optimize>
41 <OutputPath>bin\Debug\</OutputPath>
42 <DefineConstants>DEBUG;TRACE</DefineConstants>
43 <ErrorReport>prompt</ErrorReport>
44 <WarningLevel>4</WarningLevel>
45 <Prefer32Bit>false</Prefer32Bit>
46 </PropertyGroup>
13 </PropertyGroup>
47 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' ">
14
48 <DebugType>pdbonly</DebugType>
49 <Optimize>true</Optimize>
50 <OutputPath>bin\Release\</OutputPath>
51 <DefineConstants>TRACE</DefineConstants>
52 <ErrorReport>prompt</ErrorReport>
53 <WarningLevel>4</WarningLevel>
54 <Prefer32Bit>false</Prefer32Bit>
55 </PropertyGroup>
56 <ItemGroup>
15 <ItemGroup>
57 <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
16 <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.6.0-preview-20180109-01" />
58 <Reference Include="System" />
17 <PackageReference Include="System.Reactive" Version="4.0.0" />
59 <Reference Include="System.Core">
18 <PackageReference Include="xunit" Version="2.3.1" />
60 <RequiredTargetFramework>3.5</RequiredTargetFramework>
19 <PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
61 </Reference>
20 <ProjectReference Include="../Implab/Implab.csproj"/>
62 </ItemGroup>
21 <DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
63 <ItemGroup>
64 <Compile Include="AsyncTests.cs" />
65 <Compile Include="CancelationTests.cs" />
66 <Compile Include="PromiseHelper.cs" />
67 <Compile Include="Properties\AssemblyInfo.cs" />
68 <Compile Include="RunnableComponentTests.cs" />
69 </ItemGroup>
22 </ItemGroup>
70 <ItemGroup>
23
71 <ProjectReference Include="..\Implab\Implab.csproj">
24 </Project>
72 <Project>{99B95D0D-9CF9-4F70-8ADF-F4D0AA5CB0D9}</Project>
73 <Name>Implab</Name>
74 </ProjectReference>
75 </ItemGroup>
76 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
77 <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
78 Other similar extension points exist, see Microsoft.Common.targets.
79 <Target Name="BeforeBuild">
80 </Target>
81 <Target Name="AfterBuild">
82 </Target>
83 -->
84 </Project> No newline at end of file
@@ -1,88 +1,191
1 using NUnit.Framework;
1 using Xunit;
2 using System;
2 using System;
3 using Implab.Formats.JSON;
4 using Implab.Automaton;
3 using Implab.Automaton;
4 using Implab.Xml;
5 using System.Xml;
6 using Implab.Formats;
7 using Implab.Formats.Json;
8 using System.IO;
9 using Implab.Test.Model;
5
10
6 namespace Implab.Format.Test {
11 namespace Implab.Test {
7 [TestFixture]
8 public class JsonTests {
12 public class JsonTests {
9 [Test]
13
14 [Fact]
10 public void TestScannerValidTokens() {
15 public void TestScannerValidTokens() {
11 using (var scanner = new JSONScanner(@"9123, -123, 0, 0.1, -0.2, -0.1e3, 1.3E-3, ""some \t\n\u0020 text"", literal []{}:")) {
16 using (var scanner = JsonStringScanner.Create(@"9123, -123, 0, 0.1, -0.2, -0.1e3, 1.3E-3, ""some \t\n\u0020 text"", literal []{}:")) {
12
17
13 Tuple<JsonTokenType,object>[] expexted = {
18 Tuple<JsonTokenType, object>[] expexted = {
14 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 9123d),
19 new Tuple<JsonTokenType,object>(JsonTokenType.Number, "9123"),
15 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
20 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
16 new Tuple<JsonTokenType,object>(JsonTokenType.Number, -123d),
21 new Tuple<JsonTokenType,object>(JsonTokenType.Number, "-123"),
17 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
22 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
18 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 0d),
23 new Tuple<JsonTokenType,object>(JsonTokenType.Number, "0"),
19 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
24 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
20 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 0.1d),
25 new Tuple<JsonTokenType,object>(JsonTokenType.Number, "0.1"),
21 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
26 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
22 new Tuple<JsonTokenType,object>(JsonTokenType.Number, -0.2d),
27 new Tuple<JsonTokenType,object>(JsonTokenType.Number, "-0.2"),
23 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
28 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
24 new Tuple<JsonTokenType,object>(JsonTokenType.Number, -0.1e3d),
29 new Tuple<JsonTokenType,object>(JsonTokenType.Number, "-0.1e3"),
25 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
30 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
26 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 1.3E-3d),
31 new Tuple<JsonTokenType,object>(JsonTokenType.Number, "1.3E-3"),
27 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
32 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
28 new Tuple<JsonTokenType,object>(JsonTokenType.String, "some \t\n text"),
33 new Tuple<JsonTokenType,object>(JsonTokenType.String, "some \t\n text"),
29 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
34 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
30 new Tuple<JsonTokenType,object>(JsonTokenType.Literal, "literal"),
35 new Tuple<JsonTokenType,object>(JsonTokenType.Literal, "literal"),
31 new Tuple<JsonTokenType,object>(JsonTokenType.BeginArray, " ["),
36 new Tuple<JsonTokenType,object>(JsonTokenType.BeginArray, null),
32 new Tuple<JsonTokenType,object>(JsonTokenType.EndArray, "]"),
37 new Tuple<JsonTokenType,object>(JsonTokenType.EndArray, null),
33 new Tuple<JsonTokenType,object>(JsonTokenType.BeginObject, "{"),
38 new Tuple<JsonTokenType,object>(JsonTokenType.BeginObject, null),
34 new Tuple<JsonTokenType,object>(JsonTokenType.EndObject, "}"),
39 new Tuple<JsonTokenType,object>(JsonTokenType.EndObject, null),
35 new Tuple<JsonTokenType,object>(JsonTokenType.NameSeparator, ":")
40 new Tuple<JsonTokenType,object>(JsonTokenType.NameSeparator, null)
36 };
41 };
37
42
38 object value;
43 string value;
39 JsonTokenType tokenType;
44 JsonTokenType tokenType;
40 for (var i = 0; i < expexted.Length; i++) {
45 for (var i = 0; i < expexted.Length; i++) {
41
46
42 Assert.IsTrue(scanner.ReadToken(out value, out tokenType));
47 Assert.True(scanner.ReadToken(out value, out tokenType));
43 Assert.AreEqual(expexted[i].Item1, tokenType);
48 Assert.Equal(expexted[i].Item1, tokenType);
44 Assert.AreEqual(expexted[i].Item2, value);
49 Assert.Equal(expexted[i].Item2, value);
45 }
50 }
46
51
47 Assert.IsFalse(scanner.ReadToken(out value, out tokenType));
52 Assert.False(scanner.ReadToken(out value, out tokenType));
48 }
53 }
49 }
54 }
50
55
51 [Test]
56 [Fact]
52 public void TestScannerBadTokens() {
57 public void TestScannerBadTokens() {
53 var bad = new [] {
58 var bad = new[] {
54 " 1",
59 " 1",
55 " literal",
60 " literal",
56 " \"",
61 " \"",
57 "\"unclosed string",
62 "\"unclosed string",
58 "1.bad",
63 "1.bad",
59 "001", // should be read as three numbers
64 "001", // should be read as three numbers
60 "--10",
65 "--10",
61 "+10",
66 "+10",
62 "1.0.0",
67 "1.0.0",
63 "1e1.0",
68 "1e1.0",
64 "l1teral0",
69 "l1teral0",
65 ".123",
70 ".123",
66 "-.123"
71 "-.123"
67 };
72 };
68
73
69 foreach (var json in bad)
74 foreach (var json in bad) {
70 using (var scanner = new JSONScanner(json)) {
75 using (var scanner = JsonStringScanner.Create(json)) {
71 try {
76 try {
72 object value;
77 string value;
73 JsonTokenType token;
78 JsonTokenType token;
74 scanner.ReadToken(out value, out token);
79 scanner.ReadToken(out value, out token);
75 if (!Object.Equals(value,json)) {
80 if (!Object.Equals(value, json)) {
76 Console.WriteLine("'{0}' is read as {1}", json, value is String ? String.Format("'{0}'", value) : value );
81 Console.WriteLine("'{0}' is read as {1}", json, value is String ? String.Format("'{0}'", value) : value);
77 continue;
82 continue;
78 }
83 }
79 Assert.Fail("Token '{0}' shouldn't pass", json);
84 Assert.True(false, $"Token '{json}' shouldn't pass");
80 } catch (ParserException e) {
85 } catch (ParserException e) {
81 Console.WriteLine(e.Message);
86 Console.WriteLine(e.Message);
82 }
87 }
83 }
88 }
89 }
90 }
84
91
92 [Fact]
93 public void JsonXmlReaderSimpleTest() {
94 //var json = "\"some text\"";
95 //Console.WriteLine($"JSON: {json}");
96 //Console.WriteLine("XML");
97 /*using (var xmlReader = new JsonXmlReader(new JSONParser(json), new JsonXmlReaderOptions { NamespaceUri = "JsonXmlReaderSimpleTest", RootName = "string", NodesPrefix = "json" })) {
98 Assert.AreEqual(xmlReader.ReadState, System.Xml.ReadState.Initial);
99
100 AssertRead(xmlReader, XmlNodeType.XmlDeclaration);
101 AssertRead(xmlReader, XmlNodeType.Element);
102 AssertRead(xmlReader, XmlNodeType.Text);
103 AssertRead(xmlReader, XmlNodeType.EndElement);
104 Assert.IsFalse(xmlReader.Read());
105 }*/
106
107 DumpJsonParse("\"text value\"");
108 DumpJsonParse("null");
109 DumpJsonParse("true");
110 DumpJsonParse("{}");
111 DumpJsonParse("[]");
112 DumpJsonParse("{\"one\":1, \"two\":2}");
113 DumpJsonParse("[1,\"\",2,3]");
114 DumpJsonParse("[{\"info\": [7,8,9]}]");
115 DumpJsonFlatParse("[1,2,\"\",[3,4],{\"info\": [5,6]},{\"num\": [7,8,null]}, null,[null]]");
116 }
117
118 [Fact]
119 public void XmlToJsonTransform() {
120 var person = new Person {
121 FirstName = "Charlie",
122 LastName = "Brown",
123 Age = 19,
124 AgeSpecified = true
125 };
126
127 var doc = SerializationHelpers.SerializeAsXmlDocument(person);
128
129 using (var writer = new StringWriter()) {
130 XmlToJson.Default.Transform(doc,null, writer);
131 Console.WriteLine(writer.ToString());
132 }
133 }
134
135 [Fact]
136 public void JsonSerialization() {
137 var person = new Person {
138 FirstName = "Charlie",
139 LastName = "Brown",
140 Age = 19,
141 AgeSpecified = true,
142 Tags = new [] { "brave", "stupid" }
143 };
144
145 var data = SerializationHelpers.SerializeJsonAsString(person);
146 Console.WriteLine(data);
147 var clone = SerializationHelpers.DeserializeJsonFromString<Person>(data);
148
149 Assert.Equal(person.FirstName, clone.FirstName);
150 Assert.Equal(person.LastName, clone.LastName);
151 Assert.Equal(person.Age, clone.Age);
152 Assert.Equal(person.AgeSpecified, clone.AgeSpecified);
153 Assert.Equal(person.Tags, person.Tags);
154 }
155
156 void AssertRead(XmlReader reader, XmlNodeType expected) {
157 Assert.True(reader.Read());
158 Console.WriteLine($"{new string(' ', reader.Depth * 2)}{reader}");
159 Assert.Equal(expected, reader.NodeType);
160 }
161
162 void DumpJsonParse(string json) {
163 Console.WriteLine($"JSON: {json}");
164 Console.WriteLine("XML");
165 using (var xmlWriter = XmlWriter.Create(Console.Out, new XmlWriterSettings {
166 Indent = true,
167 CloseOutput = false,
168 ConformanceLevel = ConformanceLevel.Document
169 }))
170 using (var xmlReader = new JsonXmlReader(JsonReader.ParseString(json), new JsonXmlReaderOptions { NamespaceUri = "JsonXmlReaderSimpleTest", RootName = "Data", NodesPrefix = "json", CaseTransform = JsonXmlCaseTransform.UcFirst, ArrayItemName = "Item" })) {
171 xmlWriter.WriteNode(xmlReader, false);
172 }
173 Console.WriteLine();
174 }
175
176 void DumpJsonFlatParse(string json) {
177 Console.WriteLine($"JSON: {json}");
178 Console.WriteLine("XML");
179 using (var xmlWriter = XmlWriter.Create(Console.Out, new XmlWriterSettings {
180 Indent = true,
181 CloseOutput = false,
182 ConformanceLevel = ConformanceLevel.Document
183 }))
184 using (var xmlReader = new JsonXmlReader(JsonReader.ParseString(json), new JsonXmlReaderOptions { NamespaceUri = "JsonXmlReaderSimpleTest", NodesPrefix = "", FlattenArrays = true })) {
185 xmlWriter.WriteNode(xmlReader, false);
186 }
187 Console.WriteLine();
85 }
188 }
86 }
189 }
87 }
190 }
88
191
@@ -1,14 +1,40
1 using Implab.Parallels;
1 using Implab;
2 using System;
2 using System.Threading;
3 using System.Threading;
3
4
4 namespace Implab.Test {
5 namespace Implab.Test {
5 static class PromiseHelper {
6 static class PromiseHelper {
6 public static IPromise<T> Sleep<T>(int timeout, T retVal) {
7 public static IPromise<T> Sleep<T>(int timeout, T retVal, CancellationToken ct = default(CancellationToken)) {
7 return AsyncPool.Invoke((ct) => {
8
8 ct.CancellationRequested(ct.CancelOperation);
9 Timer timer = null;
9 Thread.Sleep(timeout);
10
10 return retVal;
11 return Promise.Create<T>((d) => {
12 timer = new Timer(x => {
13 d.Resolve(retVal);
14 }, null, timeout, Timeout.Infinite);
15
16 if(ct.CanBeCanceled)
17 ct.Register(d.Cancel);
18
19 }).Finally(() => {
20 Safe.Dispose(timer);
21 });
22 }
23
24 public static IPromise Sleep(int timeout, CancellationToken ct = default(CancellationToken)) {
25 Timer timer = null;
26
27 return Promise.Create((d) => {
28 timer = new Timer(x => {
29 d.Resolve();
30 }, null, timeout, Timeout.Infinite);
31
32 if(ct.CanBeCanceled)
33 ct.Register(d.Cancel);
34
35 }).Finally(() => {
36 Safe.Dispose(timer);
11 });
37 });
12 }
38 }
13 }
39 }
14 }
40 }
@@ -1,270 +1,69
1 
1
2 Microsoft Visual Studio Solution File, Format Version 11.00
2 Microsoft Visual Studio Solution File, Format Version 12.00
3 # Visual Studio 2010
3 # Visual Studio 15
4 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab", "Implab\Implab.csproj", "{F550F1F8-8746-4AD0-9614-855F4C4B7F05}"
4 VisualStudioVersion = 15.0.27428.2005
5 MinimumVisualStudioVersion = 10.0.40219.1
6 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Implab", "Implab\Implab.csproj", "{FF2052B6-9C8F-4022-A347-F07ABF635885}"
5 EndProject
7 EndProject
6 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{CE8D8D18-437A-445C-B662-4C2CE79A76F6}"
8 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Implab.Test", "Implab.Test\Implab.Test.csproj", "{6CD0DA18-8D9B-4AA8-A3DC-17322E27335E}"
7 ProjectSection(SolutionItems) = preProject
9 EndProject
8 Implab.vsmdi = Implab.vsmdi
10 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.Playground", "Implab.Playground\Implab.Playground.csproj", "{100DFEB0-75BE-436F-ADDF-1F46EF433F46}"
9 Local.testsettings = Local.testsettings
10 TraceAndTestImpact.testsettings = TraceAndTestImpact.testsettings
11 EndProjectSection
12 EndProject
11 EndProject
13 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.Test", "Implab.Test\Implab.Test.csproj", "{63F92C0C-61BF-48C0-A377-8D67C3C661D0}"
12 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.ServiceHost", "Implab.ServiceHost\Implab.ServiceHost.csproj", "{8B79FCBE-50DD-40A0-9B5E-E572072E4868}"
14 EndProject
13 EndProject
15 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.Fx", "Implab.Fx\Implab.Fx.csproj", "{06E706F8-6881-43EB-927E-FFC503AF6ABC}"
14 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.ServiceHost.Test", "Implab.ServiceHost.Test\Implab.ServiceHost.Test.csproj", "{CB844F94-E555-4F25-A932-7CB85C98CF86}"
16 EndProject
17 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.Fx.Test", "Implab.Fx.Test\Implab.Fx.Test.csproj", "{2F31E405-E267-4195-A05D-574093C21209}"
18 EndProject
15 EndProject
19 Global
16 Global
20 GlobalSection(SolutionConfigurationPlatforms) = preSolution
17 GlobalSection(SolutionConfigurationPlatforms) = preSolution
21 Debug|Any CPU = Debug|Any CPU
18 Debug|Any CPU = Debug|Any CPU
22 Release|Any CPU = Release|Any CPU
19 Release|Any CPU = Release|Any CPU
23 Debug 4.5|Any CPU = Debug 4.5|Any CPU
20 Debug|x64 = Debug|x64
24 Release 4.5|Any CPU = Release 4.5|Any CPU
21 Debug|x86 = Debug|x86
22 Release|x64 = Release|x64
23 Release|x86 = Release|x86
25 EndGlobalSection
24 EndGlobalSection
26 GlobalSection(ProjectConfigurationPlatforms) = postSolution
25 GlobalSection(ProjectConfigurationPlatforms) = postSolution
27 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
26 {FF2052B6-9C8F-4022-A347-F07ABF635885}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
28 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
27 {FF2052B6-9C8F-4022-A347-F07ABF635885}.Debug|Any CPU.Build.0 = Debug|Any CPU
29 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
28 {FF2052B6-9C8F-4022-A347-F07ABF635885}.Release|Any CPU.ActiveCfg = Release|Any CPU
30 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug|Any CPU.Build.0 = Debug|Any CPU
29 {FF2052B6-9C8F-4022-A347-F07ABF635885}.Release|Any CPU.Build.0 = Release|Any CPU
31 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
30 {6CD0DA18-8D9B-4AA8-A3DC-17322E27335E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
32 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
31 {6CD0DA18-8D9B-4AA8-A3DC-17322E27335E}.Debug|Any CPU.Build.0 = Debug|Any CPU
33 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release|Any CPU.ActiveCfg = Release|Any CPU
32 {6CD0DA18-8D9B-4AA8-A3DC-17322E27335E}.Release|Any CPU.ActiveCfg = Release|Any CPU
34 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release|Any CPU.Build.0 = Release|Any CPU
33 {6CD0DA18-8D9B-4AA8-A3DC-17322E27335E}.Release|Any CPU.Build.0 = Release|Any CPU
35 {2F31E405-E267-4195-A05D-574093C21209}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
34 {100DFEB0-75BE-436F-ADDF-1F46EF433F46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
36 {2F31E405-E267-4195-A05D-574093C21209}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
35 {100DFEB0-75BE-436F-ADDF-1F46EF433F46}.Debug|Any CPU.Build.0 = Debug|Any CPU
37 {2F31E405-E267-4195-A05D-574093C21209}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
36 {100DFEB0-75BE-436F-ADDF-1F46EF433F46}.Release|Any CPU.ActiveCfg = Release|Any CPU
38 {2F31E405-E267-4195-A05D-574093C21209}.Debug|Any CPU.Build.0 = Debug|Any CPU
37 {100DFEB0-75BE-436F-ADDF-1F46EF433F46}.Release|Any CPU.Build.0 = Release|Any CPU
39 {2F31E405-E267-4195-A05D-574093C21209}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
38 {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
40 {2F31E405-E267-4195-A05D-574093C21209}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
39 {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Debug|Any CPU.Build.0 = Debug|Any CPU
41 {2F31E405-E267-4195-A05D-574093C21209}.Release|Any CPU.ActiveCfg = Release|Any CPU
40 {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Debug|x64.ActiveCfg = Debug|x64
42 {2F31E405-E267-4195-A05D-574093C21209}.Release|Any CPU.Build.0 = Release|Any CPU
41 {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Debug|x64.Build.0 = Debug|x64
43 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
42 {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Debug|x86.ActiveCfg = Debug|x86
44 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
43 {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Debug|x86.Build.0 = Debug|x86
45 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
44 {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Release|Any CPU.ActiveCfg = Release|Any CPU
46 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
45 {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Release|Any CPU.Build.0 = Release|Any CPU
47 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
46 {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Release|x64.ActiveCfg = Release|x64
48 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
47 {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Release|x64.Build.0 = Release|x64
49 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
48 {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Release|x86.ActiveCfg = Release|x86
50 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release|Any CPU.Build.0 = Release|Any CPU
49 {8B79FCBE-50DD-40A0-9B5E-E572072E4868}.Release|x86.Build.0 = Release|x86
51 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
50 {CB844F94-E555-4F25-A932-7CB85C98CF86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
52 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
51 {CB844F94-E555-4F25-A932-7CB85C98CF86}.Debug|Any CPU.Build.0 = Debug|Any CPU
53 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
52 {CB844F94-E555-4F25-A932-7CB85C98CF86}.Debug|x64.ActiveCfg = Debug|x64
54 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug|Any CPU.Build.0 = Debug|Any CPU
53 {CB844F94-E555-4F25-A932-7CB85C98CF86}.Debug|x64.Build.0 = Debug|x64
55 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
54 {CB844F94-E555-4F25-A932-7CB85C98CF86}.Debug|x86.ActiveCfg = Debug|x86
56 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
55 {CB844F94-E555-4F25-A932-7CB85C98CF86}.Debug|x86.Build.0 = Debug|x86
57 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release|Any CPU.ActiveCfg = Release|Any CPU
56 {CB844F94-E555-4F25-A932-7CB85C98CF86}.Release|Any CPU.ActiveCfg = Release|Any CPU
58 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release|Any CPU.Build.0 = Release|Any CPU
57 {CB844F94-E555-4F25-A932-7CB85C98CF86}.Release|Any CPU.Build.0 = Release|Any CPU
59 EndGlobalSection
58 {CB844F94-E555-4F25-A932-7CB85C98CF86}.Release|x64.ActiveCfg = Release|x64
60 GlobalSection(NestedProjects) = preSolution
59 {CB844F94-E555-4F25-A932-7CB85C98CF86}.Release|x64.Build.0 = Release|x64
61 EndGlobalSection
60 {CB844F94-E555-4F25-A932-7CB85C98CF86}.Release|x86.ActiveCfg = Release|x86
62 GlobalSection(MonoDevelopProperties) = preSolution
61 {CB844F94-E555-4F25-A932-7CB85C98CF86}.Release|x86.Build.0 = Release|x86
63 StartupItem = Implab\Implab.csproj
64 Policies = $0
65 $0.CSharpFormattingPolicy = $1
66 $1.IndentSwitchBody = True
67 $1.NamespaceBraceStyle = EndOfLine
68 $1.ClassBraceStyle = EndOfLine
69 $1.InterfaceBraceStyle = EndOfLine
70 $1.StructBraceStyle = EndOfLine
71 $1.EnumBraceStyle = EndOfLine
72 $1.MethodBraceStyle = EndOfLine
73 $1.ConstructorBraceStyle = EndOfLine
74 $1.DestructorBraceStyle = EndOfLine
75 $1.BeforeMethodDeclarationParentheses = False
76 $1.BeforeMethodCallParentheses = False
77 $1.BeforeConstructorDeclarationParentheses = False
78 $1.NewLineBeforeConstructorInitializerColon = NewLine
79 $1.NewLineAfterConstructorInitializerColon = SameLine
80 $1.BeforeIndexerDeclarationBracket = False
81 $1.BeforeDelegateDeclarationParentheses = False
82 $1.NewParentheses = False
83 $1.SpacesBeforeBrackets = False
84 $1.inheritsSet = Mono
85 $1.inheritsScope = text/x-csharp
86 $1.scope = text/x-csharp
87 $0.TextStylePolicy = $2
88 $2.FileWidth = 120
89 $2.EolMarker = Unix
90 $2.inheritsSet = VisualStudio
91 $2.inheritsScope = text/plain
92 $2.scope = text/x-csharp
93 $0.DotNetNamingPolicy = $3
94 $3.DirectoryNamespaceAssociation = PrefixedHierarchical
95 $3.ResourceNamePolicy = MSBuild
96 $0.TextStylePolicy = $4
97 $4.FileWidth = 120
98 $4.TabsToSpaces = False
99 $4.inheritsSet = VisualStudio
100 $4.inheritsScope = text/plain
101 $4.scope = application/xml
102 $0.XmlFormattingPolicy = $5
103 $5.inheritsSet = Mono
104 $5.inheritsScope = application/xml
105 $5.scope = application/xml
106 $0.TextStylePolicy = $6
107 $6.FileWidth = 120
108 $6.TabsToSpaces = False
109 $6.inheritsSet = VisualStudio
110 $6.inheritsScope = text/plain
111 $6.scope = text/plain
112 $0.NameConventionPolicy = $7
113 $7.Rules = $8
114 $8.NamingRule = $9
115 $9.Name = Namespaces
116 $9.AffectedEntity = Namespace
117 $9.VisibilityMask = VisibilityMask
118 $9.NamingStyle = PascalCase
119 $9.IncludeInstanceMembers = True
120 $9.IncludeStaticEntities = True
121 $8.NamingRule = $10
122 $10.Name = Types
123 $10.AffectedEntity = Class, Struct, Enum, Delegate
124 $10.VisibilityMask = VisibilityMask
125 $10.NamingStyle = PascalCase
126 $10.IncludeInstanceMembers = True
127 $10.IncludeStaticEntities = True
128 $8.NamingRule = $11
129 $11.Name = Interfaces
130 $11.RequiredPrefixes = $12
131 $12.String = I
132 $11.AffectedEntity = Interface
133 $11.VisibilityMask = VisibilityMask
134 $11.NamingStyle = PascalCase
135 $11.IncludeInstanceMembers = True
136 $11.IncludeStaticEntities = True
137 $8.NamingRule = $13
138 $13.Name = Attributes
139 $13.RequiredSuffixes = $14
140 $14.String = Attribute
141 $13.AffectedEntity = CustomAttributes
142 $13.VisibilityMask = VisibilityMask
143 $13.NamingStyle = PascalCase
144 $13.IncludeInstanceMembers = True
145 $13.IncludeStaticEntities = True
146 $8.NamingRule = $15
147 $15.Name = Event Arguments
148 $15.RequiredSuffixes = $16
149 $16.String = EventArgs
150 $15.AffectedEntity = CustomEventArgs
151 $15.VisibilityMask = VisibilityMask
152 $15.NamingStyle = PascalCase
153 $15.IncludeInstanceMembers = True
154 $15.IncludeStaticEntities = True
155 $8.NamingRule = $17
156 $17.Name = Exceptions
157 $17.RequiredSuffixes = $18
158 $18.String = Exception
159 $17.AffectedEntity = CustomExceptions
160 $17.VisibilityMask = VisibilityMask
161 $17.NamingStyle = PascalCase
162 $17.IncludeInstanceMembers = True
163 $17.IncludeStaticEntities = True
164 $8.NamingRule = $19
165 $19.Name = Methods
166 $19.AffectedEntity = Methods
167 $19.VisibilityMask = VisibilityMask
168 $19.NamingStyle = PascalCase
169 $19.IncludeInstanceMembers = True
170 $19.IncludeStaticEntities = True
171 $8.NamingRule = $20
172 $20.Name = Static Readonly Fields
173 $20.AffectedEntity = ReadonlyField
174 $20.VisibilityMask = Internal, Protected, Public
175 $20.NamingStyle = CamelCase
176 $20.IncludeInstanceMembers = False
177 $20.IncludeStaticEntities = True
178 $8.NamingRule = $21
179 $21.Name = Fields (Non Private)
180 $21.AffectedEntity = Field
181 $21.VisibilityMask = Internal, Public
182 $21.NamingStyle = CamelCase
183 $21.IncludeInstanceMembers = True
184 $21.IncludeStaticEntities = True
185 $8.NamingRule = $22
186 $22.Name = ReadOnly Fields (Non Private)
187 $22.AffectedEntity = ReadonlyField
188 $22.VisibilityMask = Internal, Public
189 $22.NamingStyle = CamelCase
190 $22.IncludeInstanceMembers = True
191 $22.IncludeStaticEntities = False
192 $8.NamingRule = $23
193 $23.Name = Fields (Private)
194 $23.RequiredPrefixes = $24
195 $24.String = m_
196 $23.AffectedEntity = Field, ReadonlyField
197 $23.VisibilityMask = Private, Protected
198 $23.NamingStyle = CamelCase
199 $23.IncludeInstanceMembers = True
200 $23.IncludeStaticEntities = False
201 $8.NamingRule = $25
202 $25.Name = Static Fields (Private)
203 $25.RequiredPrefixes = $26
204 $26.String = _
205 $25.AffectedEntity = Field
206 $25.VisibilityMask = Private
207 $25.NamingStyle = CamelCase
208 $25.IncludeInstanceMembers = False
209 $25.IncludeStaticEntities = True
210 $8.NamingRule = $27
211 $27.Name = ReadOnly Fields (Private)
212 $27.RequiredPrefixes = $28
213 $28.String = m_
214 $27.AffectedEntity = ReadonlyField
215 $27.VisibilityMask = Private, Protected
216 $27.NamingStyle = CamelCase
217 $27.IncludeInstanceMembers = True
218 $27.IncludeStaticEntities = False
219 $8.NamingRule = $29
220 $29.Name = Constant Fields
221 $29.AffectedEntity = ConstantField
222 $29.VisibilityMask = VisibilityMask
223 $29.NamingStyle = AllUpper
224 $29.IncludeInstanceMembers = True
225 $29.IncludeStaticEntities = True
226 $8.NamingRule = $30
227 $30.Name = Properties
228 $30.AffectedEntity = Property
229 $30.VisibilityMask = VisibilityMask
230 $30.NamingStyle = PascalCase
231 $30.IncludeInstanceMembers = True
232 $30.IncludeStaticEntities = True
233 $8.NamingRule = $31
234 $31.Name = Events
235 $31.AffectedEntity = Event
236 $31.VisibilityMask = VisibilityMask
237 $31.NamingStyle = PascalCase
238 $31.IncludeInstanceMembers = True
239 $31.IncludeStaticEntities = True
240 $8.NamingRule = $32
241 $32.Name = Enum Members
242 $32.AffectedEntity = EnumMember
243 $32.VisibilityMask = VisibilityMask
244 $32.NamingStyle = PascalCase
245 $32.IncludeInstanceMembers = True
246 $32.IncludeStaticEntities = True
247 $8.NamingRule = $33
248 $33.Name = Parameters
249 $33.AffectedEntity = Parameter, LocalVariable
250 $33.VisibilityMask = VisibilityMask
251 $33.NamingStyle = CamelCase
252 $33.IncludeInstanceMembers = True
253 $33.IncludeStaticEntities = True
254 $8.NamingRule = $34
255 $34.Name = Type Parameters
256 $34.RequiredPrefixes = $35
257 $35.String = T
258 $34.AffectedEntity = TypeParameter
259 $34.VisibilityMask = VisibilityMask
260 $34.NamingStyle = PascalCase
261 $34.IncludeInstanceMembers = True
262 $34.IncludeStaticEntities = True
263 EndGlobalSection
264 GlobalSection(TestCaseManagementSettings) = postSolution
265 CategoryFile = Implab.vsmdi
266 EndGlobalSection
62 EndGlobalSection
267 GlobalSection(SolutionProperties) = preSolution
63 GlobalSection(SolutionProperties) = preSolution
268 HideSolutionNode = FALSE
64 HideSolutionNode = FALSE
269 EndGlobalSection
65 EndGlobalSection
66 GlobalSection(ExtensibilityGlobals) = postSolution
67 SolutionGuid = {36D837FC-4CDD-4AEA-87BF-F130FEB22E02}
68 EndGlobalSection
270 EndGlobal
69 EndGlobal
@@ -1,277 +1,26
1 <?xml version="1.0" encoding="utf-8"?>
1 <Project Sdk="Microsoft.NET.Sdk">
2 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2
3 <PropertyGroup>
3 <PropertyGroup>
4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
4 <Authors>Sergey Smirnov</Authors>
5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
5 <Title>Implab library</Title>
6 <ProjectGuid>{F550F1F8-8746-4AD0-9614-855F4C4B7F05}</ProjectGuid>
6 <Description>Provides some helper clesses like XML serialization helpers, JSON XML reader,
7 <OutputType>Library</OutputType>
7 JSON pull-parser, ECMA-style promises, lightweight synchonization routines Signal
8 <RootNamespace>Implab</RootNamespace>
8 and SharedLock, Trace helpers on top of System.Diagnostics, ObjectPool etc.
9 <AssemblyName>Implab</AssemblyName>
9 </Description>
10 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
10 <Copyright>2012-2018 Sergey Smirnov</Copyright>
11 <ProductVersion>8.0.30703</ProductVersion>
11 <Version>3.0.14</Version>
12 <SchemaVersion>2.0</SchemaVersion>
12 <PackageLicenseUrl>https://bitbucket.org/wozard/implabnet/src/v3/Implab/license.txt</PackageLicenseUrl>
13 </PropertyGroup>
13 <PackageProjectUrl>https://bitbucket.org/wozard/implabnet</PackageProjectUrl>
14 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
14 <RepositoryUrl>https://bitbucket.org/wozard/implabnet</RepositoryUrl>
15 <DebugSymbols>true</DebugSymbols>
15 <RepositoryType>mercurial</RepositoryType>
16 <DebugType>full</DebugType>
16 <PackageTags>IMPLAB;Json pull-parser;Json Xml;async;diagnostics;serialization;</PackageTags>
17 <Optimize>false</Optimize>
17 <TargetFrameworks>netstandard2.0;net46</TargetFrameworks>
18 <OutputPath>bin\Debug</OutputPath>
18 <FrameworkPathOverride Condition="'$(TargetFramework)'=='net46' and '$(OSTYPE)'=='linux'">/usr/lib/mono/4.5/</FrameworkPathOverride>
19 <DefineConstants>TRACE;DEBUG;</DefineConstants>
19 <DefineConstants Condition="'$(TargetFramework)'=='net46'">NETFX_TRACE_BUG;$(DefineConstants)</DefineConstants>
20 <ErrorReport>prompt</ErrorReport>
21 <WarningLevel>4</WarningLevel>
22 <ConsolePause>false</ConsolePause>
23 <RunCodeAnalysis>true</RunCodeAnalysis>
24 </PropertyGroup>
25 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
26 <DebugType>full</DebugType>
27 <Optimize>true</Optimize>
28 <OutputPath>bin\Release</OutputPath>
29 <ErrorReport>prompt</ErrorReport>
30 <WarningLevel>4</WarningLevel>
31 <ConsolePause>false</ConsolePause>
32 </PropertyGroup>
20 </PropertyGroup>
33 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' ">
21
34 <DebugSymbols>true</DebugSymbols>
35 <DebugType>full</DebugType>
36 <Optimize>false</Optimize>
37 <OutputPath>bin\Debug</OutputPath>
38 <DefineConstants>TRACE;DEBUG;NET_4_5</DefineConstants>
39 <ErrorReport>prompt</ErrorReport>
40 <WarningLevel>4</WarningLevel>
41 <RunCodeAnalysis>true</RunCodeAnalysis>
42 <ConsolePause>false</ConsolePause>
43 </PropertyGroup>
44 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' ">
45 <Optimize>true</Optimize>
46 <OutputPath>bin\Release</OutputPath>
47 <ErrorReport>prompt</ErrorReport>
48 <WarningLevel>4</WarningLevel>
49 <ConsolePause>false</ConsolePause>
50 <DefineConstants>NET_4_5</DefineConstants>
51 </PropertyGroup>
52 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'DebugMono|AnyCPU' ">
53 <DebugSymbols>true</DebugSymbols>
54 <DebugType>full</DebugType>
55 <Optimize>false</Optimize>
56 <OutputPath>bin\Debug</OutputPath>
57 <DefineConstants>TRACE;DEBUG;NET_4_5;MONO</DefineConstants>
58 <ErrorReport>prompt</ErrorReport>
59 <WarningLevel>4</WarningLevel>
60 <RunCodeAnalysis>true</RunCodeAnalysis>
61 <ConsolePause>false</ConsolePause>
62 </PropertyGroup>
63 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseMono|AnyCPU' ">
64 <Optimize>true</Optimize>
65 <OutputPath>bin\Release</OutputPath>
66 <DefineConstants>NET_4_5;MONO;</DefineConstants>
67 <ErrorReport>prompt</ErrorReport>
68 <WarningLevel>4</WarningLevel>
69 <ConsolePause>false</ConsolePause>
70 </PropertyGroup>
71 <ItemGroup>
72 <Reference Include="System" />
73 <Reference Include="System.Xml" />
74 <Reference Include="mscorlib" />
75 </ItemGroup>
76 <ItemGroup>
22 <ItemGroup>
77 <Compile Include="CustomEqualityComparer.cs" />
23 <EmbeddedResource Include="src\Xml\json.xsl"/>
78 <Compile Include="Diagnostics\ConsoleTraceListener.cs" />
79 <Compile Include="Diagnostics\EventText.cs" />
80 <Compile Include="Diagnostics\LogChannel.cs" />
81 <Compile Include="Diagnostics\LogicalOperation.cs" />
82 <Compile Include="Diagnostics\TextFileListener.cs" />
83 <Compile Include="Diagnostics\TraceLog.cs" />
84 <Compile Include="Diagnostics\TraceEvent.cs" />
85 <Compile Include="Diagnostics\TraceEventType.cs" />
86 <Compile Include="ICancellable.cs" />
87 <Compile Include="IProgressHandler.cs" />
88 <Compile Include="IProgressNotifier.cs" />
89 <Compile Include="IPromiseT.cs" />
90 <Compile Include="IPromise.cs" />
91 <Compile Include="IServiceLocator.cs" />
92 <Compile Include="ITaskController.cs" />
93 <Compile Include="Parallels\DispatchPool.cs" />
94 <Compile Include="Parallels\ArrayTraits.cs" />
95 <Compile Include="Parallels\MTQueue.cs" />
96 <Compile Include="Parallels\WorkerPool.cs" />
97 <Compile Include="ProgressInitEventArgs.cs" />
98 <Compile Include="Properties\AssemblyInfo.cs" />
99 <Compile Include="Parallels\AsyncPool.cs" />
100 <Compile Include="Safe.cs" />
101 <Compile Include="ValueEventArgs.cs" />
102 <Compile Include="PromiseExtensions.cs" />
103 <Compile Include="SyncContextPromise.cs" />
104 <Compile Include="Diagnostics\OperationContext.cs" />
105 <Compile Include="Diagnostics\TraceContext.cs" />
106 <Compile Include="Diagnostics\LogEventArgs.cs" />
107 <Compile Include="Diagnostics\LogEventArgsT.cs" />
108 <Compile Include="Diagnostics\Extensions.cs" />
109 <Compile Include="PromiseEventType.cs" />
110 <Compile Include="Parallels\AsyncQueue.cs" />
111 <Compile Include="PromiseT.cs" />
112 <Compile Include="IDeferred.cs" />
113 <Compile Include="IDeferredT.cs" />
114 <Compile Include="Promise.cs" />
115 <Compile Include="PromiseTransientException.cs" />
116 <Compile Include="Parallels\Signal.cs" />
117 <Compile Include="Parallels\SharedLock.cs" />
118 <Compile Include="Diagnostics\ILogWriter.cs" />
119 <Compile Include="Diagnostics\ListenerBase.cs" />
120 <Compile Include="Parallels\BlockingQueue.cs" />
121 <Compile Include="AbstractEvent.cs" />
122 <Compile Include="AbstractPromise.cs" />
123 <Compile Include="AbstractPromiseT.cs" />
124 <Compile Include="FuncTask.cs" />
125 <Compile Include="FuncTaskBase.cs" />
126 <Compile Include="FuncTaskT.cs" />
127 <Compile Include="ActionChainTaskBase.cs" />
128 <Compile Include="ActionChainTask.cs" />
129 <Compile Include="ActionChainTaskT.cs" />
130 <Compile Include="FuncChainTaskBase.cs" />
131 <Compile Include="FuncChainTask.cs" />
132 <Compile Include="FuncChainTaskT.cs" />
133 <Compile Include="ActionTaskBase.cs" />
134 <Compile Include="ActionTask.cs" />
135 <Compile Include="ActionTaskT.cs" />
136 <Compile Include="ICancellationToken.cs" />
137 <Compile Include="SuccessPromise.cs" />
138 <Compile Include="SuccessPromiseT.cs" />
139 <Compile Include="PromiseAwaiterT.cs" />
140 <Compile Include="PromiseAwaiter.cs" />
141 <Compile Include="Components\ComponentContainer.cs" />
142 <Compile Include="Components\Disposable.cs" />
143 <Compile Include="Components\DisposablePool.cs" />
144 <Compile Include="Components\ObjectPool.cs" />
145 <Compile Include="Components\ServiceLocator.cs" />
146 <Compile Include="Components\IInitializable.cs" />
147 <Compile Include="TaskController.cs" />
148 <Compile Include="Components\App.cs" />
149 <Compile Include="Components\IRunnable.cs" />
150 <Compile Include="Components\ExecutionState.cs" />
151 <Compile Include="Components\RunnableComponent.cs" />
152 <Compile Include="Components\IFactory.cs" />
153 <Compile Include="Automaton\IAlphabet.cs" />
154 <Compile Include="Automaton\ParserException.cs" />
155 <Compile Include="Automaton\IndexedAlphabetBase.cs" />
156 <Compile Include="Automaton\IAlphabetBuilder.cs" />
157 <Compile Include="Automaton\RegularExpressions\AltToken.cs" />
158 <Compile Include="Automaton\RegularExpressions\BinaryToken.cs" />
159 <Compile Include="Automaton\RegularExpressions\CatToken.cs" />
160 <Compile Include="Automaton\RegularExpressions\StarToken.cs" />
161 <Compile Include="Automaton\RegularExpressions\SymbolToken.cs" />
162 <Compile Include="Automaton\RegularExpressions\EmptyToken.cs" />
163 <Compile Include="Automaton\RegularExpressions\Token.cs" />
164 <Compile Include="Automaton\RegularExpressions\IVisitor.cs" />
165 <Compile Include="Automaton\AutomatonTransition.cs" />
166 <Compile Include="Formats\JSON\JSONElementContext.cs" />
167 <Compile Include="Formats\JSON\JSONElementType.cs" />
168 <Compile Include="Formats\JSON\JSONGrammar.cs" />
169 <Compile Include="Formats\JSON\JSONParser.cs" />
170 <Compile Include="Formats\JSON\JSONScanner.cs" />
171 <Compile Include="Formats\JSON\JsonTokenType.cs" />
172 <Compile Include="Formats\JSON\JSONWriter.cs" />
173 <Compile Include="Formats\JSON\JSONXmlReader.cs" />
174 <Compile Include="Formats\JSON\JSONXmlReaderOptions.cs" />
175 <Compile Include="Formats\JSON\StringTranslator.cs" />
176 <Compile Include="Automaton\MapAlphabet.cs" />
177 <Compile Include="Formats\CharAlphabet.cs" />
178 <Compile Include="Formats\ByteAlphabet.cs" />
179 <Compile Include="Automaton\IDFATable.cs" />
180 <Compile Include="Automaton\IDFATableBuilder.cs" />
181 <Compile Include="Automaton\DFATable.cs" />
182 <Compile Include="Automaton\RegularExpressions\RegularExpressionVisitor.cs" />
183 <Compile Include="Automaton\RegularExpressions\ITaggedDFABuilder.cs" />
184 <Compile Include="Formats\TextScanner.cs" />
185 <Compile Include="Formats\StringScanner.cs" />
186 <Compile Include="Formats\ReaderScanner.cs" />
187 <Compile Include="Formats\ScannerContext.cs" />
188 <Compile Include="Formats\Grammar.cs" />
189 <Compile Include="Automaton\RegularExpressions\EndTokenT.cs" />
190 <Compile Include="Automaton\RegularExpressions\EndToken.cs" />
191 <Compile Include="Automaton\RegularExpressions\RegularExpressionVisitorT.cs" />
192 <Compile Include="Automaton\AutomatonConst.cs" />
193 <Compile Include="Automaton\RegularExpressions\RegularDFA.cs" />
194 <Compile Include="Components\LazyAndWeak.cs" />
195 <Compile Include="AbstractTask.cs" />
196 <Compile Include="AbstractTaskT.cs" />
197 </ItemGroup>
24 </ItemGroup>
198 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
25
199 <ItemGroup />
26 </Project>
200 <ProjectExtensions>
201 <MonoDevelop>
202 <Properties>
203 <Policies>
204 <CSharpFormattingPolicy IndentBlock="True" IndentBraces="False" IndentSwitchSection="False" IndentSwitchCaseSection="True" LabelPositioning="OneLess" NewLinesForBracesInTypes="True" NewLinesForBracesInMethods="True" NewLinesForBracesInProperties="False" NewLinesForBracesInAccessors="False" NewLinesForBracesInAnonymousMethods="False" NewLinesForBracesInControlBlocks="False" NewLinesForBracesInAnonymousTypes="False" NewLinesForBracesInObjectCollectionArrayInitializers="False" NewLinesForBracesInLambdaExpressionBody="False" NewLineForElse="False" NewLineForCatch="False" NewLineForFinally="False" NewLineForMembersInObjectInit="False" NewLineForMembersInAnonymousTypes="False" NewLineForClausesInQuery="False" SpacingAfterMethodDeclarationName="True" SpaceWithinMethodDeclarationParenthesis="False" SpaceBetweenEmptyMethodDeclarationParentheses="False" SpaceAfterMethodCallName="True" SpaceWithinMethodCallParentheses="False" SpaceBetweenEmptyMethodCallParentheses="False" SpaceAfterControlFlowStatementKeyword="True" SpaceWithinExpressionParentheses="False" SpaceWithinCastParentheses="False" SpaceWithinOtherParentheses="False" SpaceAfterCast="False" SpacesIgnoreAroundVariableDeclaration="False" SpaceBeforeOpenSquareBracket="True" SpaceBetweenEmptySquareBrackets="False" SpaceWithinSquareBrackets="False" SpaceAfterColonInBaseTypeDeclaration="True" SpaceAfterComma="True" SpaceAfterDot="False" SpaceAfterSemicolonsInForStatement="True" SpaceBeforeColonInBaseTypeDeclaration="True" SpaceBeforeComma="False" SpaceBeforeDot="False" SpaceBeforeSemicolonsInForStatement="False" SpacingAroundBinaryOperator="Single" WrappingPreserveSingleLine="True" WrappingKeepStatementsOnSingleLine="True" PlaceSystemDirectiveFirst="True" scope="text/x-csharp" />
205 <TextStylePolicy FileWidth="120" TabWidth="4" IndentWidth="4" RemoveTrailingWhitespace="True" NoTabsAfterNonTabs="False" TabsToSpaces="True" EolMarker="Unix" scope="text/x-csharp" />
206 <DotNetNamingPolicy DirectoryNamespaceAssociation="PrefixedHierarchical" ResourceNamePolicy="MSBuild" />
207 <TextStylePolicy FileWidth="120" TabWidth="4" TabsToSpaces="False" IndentWidth="4" RemoveTrailingWhitespace="True" NoTabsAfterNonTabs="False" EolMarker="Native" scope="application/xml" />
208 <XmlFormattingPolicy scope="application/xml">
209 <DefaultFormat OmitXmlDeclaration="False" NewLineChars="&#xA;" IndentContent="True" ContentIndentString="&#x9;" AttributesInNewLine="False" MaxAttributesPerLine="10" AttributesIndentString="&#x9;" WrapAttributes="False" AlignAttributes="False" AlignAttributeValues="False" QuoteChar="&quot;" SpacesBeforeAssignment="0" SpacesAfterAssignment="0" EmptyLinesBeforeStart="0" EmptyLinesAfterStart="0" EmptyLinesBeforeEnd="0" EmptyLinesAfterEnd="0" />
210 </XmlFormattingPolicy>
211 <TextStylePolicy FileWidth="120" TabWidth="4" TabsToSpaces="False" IndentWidth="4" RemoveTrailingWhitespace="True" NoTabsAfterNonTabs="False" EolMarker="Native" scope="text/plain" />
212 <NameConventionPolicy>
213 <Rules>
214 <NamingRule Name="Namespaces" AffectedEntity="Namespace" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
215 <NamingRule Name="Types" AffectedEntity="Class, Struct, Enum, Delegate" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
216 <NamingRule Name="Interfaces" AffectedEntity="Interface" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
217 <RequiredPrefixes>
218 <String>I</String>
219 </RequiredPrefixes>
220 </NamingRule>
221 <NamingRule Name="Attributes" AffectedEntity="CustomAttributes" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
222 <RequiredSuffixes>
223 <String>Attribute</String>
224 </RequiredSuffixes>
225 </NamingRule>
226 <NamingRule Name="Event Arguments" AffectedEntity="CustomEventArgs" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
227 <RequiredSuffixes>
228 <String>EventArgs</String>
229 </RequiredSuffixes>
230 </NamingRule>
231 <NamingRule Name="Exceptions" AffectedEntity="CustomExceptions" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
232 <RequiredSuffixes>
233 <String>Exception</String>
234 </RequiredSuffixes>
235 </NamingRule>
236 <NamingRule Name="Methods" AffectedEntity="Methods" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
237 <NamingRule Name="Static Readonly Fields" AffectedEntity="ReadonlyField" VisibilityMask="Internal, Protected, Public" NamingStyle="CamelCase" IncludeInstanceMembers="False" IncludeStaticEntities="True" />
238 <NamingRule Name="Fields (Non Private)" AffectedEntity="Field" VisibilityMask="Internal, Public" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
239 <NamingRule Name="ReadOnly Fields (Non Private)" AffectedEntity="ReadonlyField" VisibilityMask="Internal, Public" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False" />
240 <NamingRule Name="Fields (Private)" AffectedEntity="Field, ReadonlyField" VisibilityMask="Private, Protected" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False">
241 <RequiredPrefixes>
242 <String>m_</String>
243 </RequiredPrefixes>
244 </NamingRule>
245 <NamingRule Name="Static Fields (Private)" AffectedEntity="Field" VisibilityMask="Private" NamingStyle="CamelCase" IncludeInstanceMembers="False" IncludeStaticEntities="True">
246 <RequiredPrefixes>
247 <String>_</String>
248 </RequiredPrefixes>
249 </NamingRule>
250 <NamingRule Name="ReadOnly Fields (Private)" AffectedEntity="ReadonlyField" VisibilityMask="Private, Protected" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False">
251 <RequiredPrefixes>
252 <String>m_</String>
253 </RequiredPrefixes>
254 </NamingRule>
255 <NamingRule Name="Constant Fields" AffectedEntity="ConstantField" VisibilityMask="VisibilityMask" NamingStyle="AllUpper" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
256 <NamingRule Name="Properties" AffectedEntity="Property" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
257 <NamingRule Name="Events" AffectedEntity="Event" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
258 <NamingRule Name="Enum Members" AffectedEntity="EnumMember" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
259 <NamingRule Name="Parameters" AffectedEntity="Parameter, LocalVariable" VisibilityMask="VisibilityMask" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
260 <NamingRule Name="Type Parameters" AffectedEntity="TypeParameter" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
261 <RequiredPrefixes>
262 <String>T</String>
263 </RequiredPrefixes>
264 </NamingRule>
265 </Rules>
266 </NameConventionPolicy>
267 </Policies>
268 </Properties>
269 </MonoDevelop>
270 </ProjectExtensions>
271 <ItemGroup>
272 <Folder Include="Components\" />
273 <Folder Include="Automaton\RegularExpressions\" />
274 <Folder Include="Formats\" />
275 <Folder Include="Formats\JSON\" />
276 </ItemGroup>
277 </Project> No newline at end of file
@@ -1,300 +1,130
1 using System;
1 using System;
2 using Implab.Parallels;
2 using Implab.Parallels;
3 using System.Threading;
3 using System.Threading;
4 using System.Reflection;
4 using System.Reflection;
5 using System.Diagnostics;
5
6
6 namespace Implab {
7 namespace Implab {
7 public abstract class AbstractEvent<THandler> : ICancellationToken, ICancellable {
8 /// <summary>
8
9 /// Abstract class for creation of custom one-shot thread safe events.
9 const int UNRESOLVED_SATE = 0;
10 /// </summary>
10 const int TRANSITIONAL_STATE = 1;
11 /// <remarks>
11 protected const int SUCCEEDED_STATE = 2;
12 /// <para>
12 protected const int REJECTED_STATE = 3;
13 /// An event is something that should happen in the future and the
13 protected const int CANCELLED_STATE = 4;
14 /// triggering of the event causes execution of some pending actions
14
15 /// which are formely event handlers. One-shot events occur only once
15 const int CANCEL_NOT_REQUESTED = 0;
16 /// and any handler added after the event is triggered should run
16 const int CANCEL_REQUESTING = 1;
17 /// without a delay.
17 const int CANCEL_REQUESTED = 2;
18 /// </para>
18
19 /// <para>
19 const int RESERVED_HANDLERS_COUNT = 4;
20 /// The lifecycle of the one-shot event is tipically consists of following
20
21 /// phases.
21 int m_state;
22 /// <list>
22 Exception m_error;
23 /// <description>Pending state. This is the initial state of the event. Any
23 int m_handlersCount;
24 /// handler added to the event will be queued for the future execution.
25 /// </description>
26 /// <description>Transitional state. This is intermediate state between pending
27 /// and fulfilled states, during this state internal initialization and storing
28 /// of the result occurs.
29 /// </description>
30 /// <description>Fulfilled state. The event contains the result, all queued
31 /// handlers are signalled to run and newly added handlers are executed
32 /// immediatelly.
33 /// </description>
34 /// </list>
35 /// </para>
36 /// </remarks>
37 public abstract class AbstractEvent<THandler> where THandler : class {
38 const int PendingState = 0;
24
39
25 //readonly THandler[] m_handlers = new THandler[RESERVED_HANDLERS_COUNT];
40 const int TransitionalState = 1;
26 THandler[] m_handlers;
27 MTQueue<THandler> m_extraHandlers;
28 int m_handlerPointer = -1;
29 int m_handlersCommited;
30
41
31 int m_cancelRequest;
42 const int ResolvedState = 2;
32 Exception m_cancelationReason;
33 MTQueue<Action<Exception>> m_cancelationHandlers;
34
43
44 volatile int m_state;
35
45
36 #region state managment
46 THandler m_handler;
37 bool BeginTransit() {
47 SimpleAsyncQueue<THandler> m_extraHandlers;
38 return UNRESOLVED_SATE == Interlocked.CompareExchange(ref m_state, TRANSITIONAL_STATE, UNRESOLVED_SATE);
39 }
40
48
41 void CompleteTransit(int state) {
49 public bool IsResolved {
42 if (TRANSITIONAL_STATE != Interlocked.CompareExchange(ref m_state, state, TRANSITIONAL_STATE))
50 get {
43 throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state");
51 return m_state > TransitionalState;
44 }
45
46 void WaitTransition() {
47 while (m_state == TRANSITIONAL_STATE) {
48 Thread.MemoryBarrier();
49 }
52 }
50 }
53 }
51
54
52 protected bool BeginSetResult() {
55 #region state managment
53 if (!BeginTransit()) {
56 protected bool BeginTransit() {
54 WaitTransition();
57 return PendingState == Interlocked.CompareExchange(ref m_state, TransitionalState, PendingState);
55 if (m_state != CANCELLED_STATE)
56 throw new InvalidOperationException("The promise is already resolved");
57 return false;
58 }
59 return true;
60 }
58 }
61
59
62 protected void EndSetResult() {
60 protected void CompleteTransit() {
63 CompleteTransit(SUCCEEDED_STATE);
61 #if DEBUG
62 if (TransitionalState != Interlocked.CompareExchange(ref m_state, ResolvedState, TransitionalState))
63 throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state");
64 #else
65 m_state = ResolvedState;
66 #endif
64 Signal();
67 Signal();
65 }
68 }
66
69
70 protected void WaitTransition() {
71 if (m_state == TransitionalState) {
72 SpinWait spin = new SpinWait();
73 do {
74 spin.SpinOnce();
75 } while (m_state == TransitionalState);
76 }
77 }
78
67
79
68
80 protected abstract void SignalHandler(THandler handler);
69 /// <summary>
70 /// Выполняет обещание, сообщая об ошибке
71 /// </summary>
72 /// <remarks>
73 /// Поскольку обещание должно работать в многопточной среде, при его выполнении сразу несколько потоков
74 /// могу вернуть ошибку, при этом только первая будет использована в качестве результата, остальные
75 /// будут проигнорированы.
76 /// </remarks>
77 /// <param name="error">Исключение возникшее при выполнении операции</param>
78 /// <exception cref="InvalidOperationException">Данное обещание уже выполнено</exception>
79 protected void SetError(Exception error) {
80 if (BeginTransit()) {
81 m_error = error;
82 CompleteTransit(REJECTED_STATE);
83
84 Signal();
85 } else {
86 WaitTransition();
87 if (m_state == SUCCEEDED_STATE)
88 throw new InvalidOperationException("The promise is already resolved");
89 }
90 }
91
92 /// <summary>
93 /// Отменяет операцию, если это возможно.
94 /// </summary>
95 /// <remarks>Для определения была ли операция отменена следует использовать свойство <see cref="IsCancelled"/>.</remarks>
96 protected void SetCancelled(Exception reason) {
97 if (BeginTransit()) {
98 m_error = reason;
99 CompleteTransit(CANCELLED_STATE);
100 Signal();
101 }
102 }
103
104 protected abstract void SignalHandler(THandler handler, int signal);
105
81
106 void Signal() {
82 void Signal() {
107 var hp = m_handlerPointer;
108 var slot = hp +1 ;
109 while (slot < m_handlersCommited) {
110 if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) {
111 SignalHandler(m_handlers[slot], m_state);
112 }
113 hp = m_handlerPointer;
114 slot = hp +1 ;
115 }
116
117
118 if (m_extraHandlers != null) {
119 THandler handler;
83 THandler handler;
120 while (m_extraHandlers.TryDequeue(out handler))
84 while (TryDequeueHandler(out handler))
121 SignalHandler(handler, m_state);
85 SignalHandler(handler);
122 }
123 }
86 }
124
87
125 #endregion
88 #endregion
126
89
127 protected abstract Signal GetResolveSignal();
128
129 #region synchronization traits
130 protected void WaitResult(int timeout) {
131 if (!(IsResolved || GetResolveSignal().Wait(timeout)))
132 throw new TimeoutException();
133
134 switch (m_state) {
135 case SUCCEEDED_STATE:
136 return;
137 case CANCELLED_STATE:
138 throw new OperationCanceledException("The operation has been cancelled", m_error);
139 case REJECTED_STATE:
140 throw new TargetInvocationException(m_error);
141 default:
142 throw new ApplicationException(String.Format("The promise state {0} is invalid", m_state));
143 }
144 }
145 #endregion
146
147 #region handlers managment
90 #region handlers managment
148
91
149 protected void AddHandler(THandler handler) {
92 protected void AddHandler(THandler handler) {
150
93
151 if (m_state > 1) {
94 if (IsResolved) {
152 // the promise is in the resolved state, just invoke the handler
95 // the promise is in the resolved state, just invoke the handler
153 SignalHandler(handler, m_state);
96 SignalHandler(handler);
154 } else {
97 } else {
155 var slot = Interlocked.Increment(ref m_handlersCount) - 1;
98 EnqueueHandler(handler);
156
157 if (slot < RESERVED_HANDLERS_COUNT) {
158
159 if (slot == 0) {
160 m_handlers = new THandler[RESERVED_HANDLERS_COUNT];
161 } else {
162 while (m_handlers == null)
163 Thread.MemoryBarrier();
164 }
165
166 m_handlers[slot] = handler;
167
168 while (slot != Interlocked.CompareExchange(ref m_handlersCommited, slot + 1, slot)) {
169 }
170
99
171 if (m_state > 1) {
100 if (IsResolved && TryDequeueHandler(out handler))
172 do {
173 var hp = m_handlerPointer;
174 slot = hp + 1;
175 if (slot < m_handlersCommited) {
176 if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) != hp)
177 continue;
178 SignalHandler(m_handlers[slot], m_state);
179 }
180 break;
181 } while(true);
182 }
183 } else {
184 if (slot == RESERVED_HANDLERS_COUNT) {
185 m_extraHandlers = new MTQueue<THandler>();
186 } else {
187 while (m_extraHandlers == null)
188 Thread.MemoryBarrier();
189 }
190
191 m_extraHandlers.Enqueue(handler);
192
193 if (m_state > 1 && m_extraHandlers.TryDequeue(out handler))
194 // if the promise have been resolved while we was adding the handler to the queue
101 // if the promise have been resolved while we was adding the handler to the queue
195 // we can't guarantee that someone is still processing it
102 // we can't guarantee that someone is still processing it
196 // therefore we need to fetch a handler from the queue and execute it
103 // therefore we need to fetch a handler from the queue and execute it
197 // note that fetched handler may be not the one that we have added
104 // note that fetched handler may be not the one that we have added
198 // even we can fetch no handlers at all :)
105 // even we can fetch no handlers at all :)
199 SignalHandler(handler, m_state);
106 SignalHandler(handler);
200 }
107 }
201 }
108
202 }
109 }
203
110
204 #endregion
111 void EnqueueHandler(THandler handler) {
205
112 if (Interlocked.CompareExchange(ref m_handler, handler, null) != null) {
206 #region IPromise implementation
113 if (m_extraHandlers == null)
207
114 // compare-exchange will protect from loosing already created queue
208 public bool IsResolved {
115 Interlocked.CompareExchange(ref m_extraHandlers, new SimpleAsyncQueue<THandler>(), null);
209 get {
116 m_extraHandlers.Enqueue(handler);
210 Thread.MemoryBarrier();
211 return m_state > 1;
212 }
213 }
214
215 public bool IsCancelled {
216 get {
217 Thread.MemoryBarrier();
218 return m_state == CANCELLED_STATE;
219 }
220 }
221
222 #endregion
223
224 public Exception Error {
225 get {
226 return m_error;
227 }
117 }
228 }
118 }
229
119
230 public bool CancelOperationIfRequested() {
120 bool TryDequeueHandler(out THandler handler) {
231 if (IsCancellationRequested) {
121 handler = Interlocked.Exchange(ref m_handler, null);
232 CancelOperation(CancellationReason);
122 if (handler != null)
233 return true;
123 return true;
234 }
124 return m_extraHandlers != null && m_extraHandlers.TryDequeue(out handler);
235 return false;
236 }
237
238 public virtual void CancelOperation(Exception reason) {
239 SetCancelled(reason);
240 }
241
242 public void CancellationRequested(Action<Exception> handler) {
243 Safe.ArgumentNotNull(handler, "handler");
244 if (IsCancellationRequested)
245 handler(CancellationReason);
246
247 if (m_cancelationHandlers == null)
248 Interlocked.CompareExchange(ref m_cancelationHandlers, new MTQueue<Action<Exception>>(), null);
249
250 m_cancelationHandlers.Enqueue(handler);
251
252 if (IsCancellationRequested && m_cancelationHandlers.TryDequeue(out handler))
253 // TryDeque implies MemoryBarrier()
254 handler(m_cancelationReason);
255 }
256
257 public bool IsCancellationRequested {
258 get {
259 do {
260 if (m_cancelRequest == CANCEL_NOT_REQUESTED)
261 return false;
262 if (m_cancelRequest == CANCEL_REQUESTED)
263 return true;
264 Thread.MemoryBarrier();
265 } while(true);
266 }
267 }
268
269 public Exception CancellationReason {
270 get {
271 do {
272 Thread.MemoryBarrier();
273 } while(m_cancelRequest == CANCEL_REQUESTING);
274
275 return m_cancelationReason;
276 }
277 }
278
279 #region ICancellable implementation
280
281 public void Cancel() {
282 Cancel(null);
283 }
284
285 public void Cancel(Exception reason) {
286 if (CANCEL_NOT_REQUESTED == Interlocked.CompareExchange(ref m_cancelRequest, CANCEL_REQUESTING, CANCEL_NOT_REQUESTED)) {
287 m_cancelationReason = reason;
288 m_cancelRequest = CANCEL_REQUESTED;
289 if (m_cancelationHandlers != null) {
290 Action<Exception> handler;
291 while (m_cancelationHandlers.TryDequeue(out handler))
292 handler(m_cancelationReason);
293 }
294 }
295 }
125 }
296
126
297 #endregion
127 #endregion
298 }
128 }
299 }
129 }
300
130
@@ -1,9 +1,9
1
1
2 namespace Implab.Automaton {
2 namespace Implab.Automaton {
3 public static class AutomatonConst {
3 public static class AutomatonConst {
4 public const int UNREACHABLE_STATE = -1;
4 public const int UnreachableState = -1;
5
5
6 public const int UNCLASSIFIED_INPUT = 0;
6 public const int UnclassifiedInput = 0;
7 }
7 }
8 }
8 }
9
9
@@ -1,33 +1,41
1 using System;
1 using System;
2
2
3 namespace Implab.Automaton {
3 namespace Implab.Automaton {
4 public struct AutomatonTransition : IEquatable<AutomatonTransition> {
4 public class AutomatonTransition : IEquatable<AutomatonTransition> {
5 public readonly int s1;
5 public readonly int s1;
6 public readonly int s2;
6 public readonly int s2;
7 public readonly int edge;
7 public readonly int edge;
8
8
9 public AutomatonTransition(int s1, int s2, int edge) {
9 public AutomatonTransition(int s1, int s2, int edge) {
10 this.s1 = s1;
10 this.s1 = s1;
11 this.s2 = s2;
11 this.s2 = s2;
12 this.edge = edge;
12 this.edge = edge;
13 }
13 }
14
14
15
15
16 #region IEquatable implementation
16 #region IEquatable implementation
17 public bool Equals(AutomatonTransition other) {
17 public bool Equals(AutomatonTransition other) {
18 return other.s1 == s1 && other.s2 == s2 && other.edge == edge ;
18 return other.s1 == s1 && other.s2 == s2 && other.edge == edge ;
19 }
19 }
20 #endregion
20 #endregion
21
21
22 public override bool Equals(object obj) {
22 public override bool Equals(object obj) {
23 if (obj is AutomatonTransition)
23 if (obj is AutomatonTransition)
24 return Equals((AutomatonTransition)obj);
24 return Equals((AutomatonTransition)obj);
25 return base.Equals(obj);
25 return base.Equals(obj);
26 }
26 }
27
27
28 public override int GetHashCode() {
28 public override int GetHashCode() {
29 return s1 + s2 + edge;
29 return s1 + s2 + edge;
30 }
30 }
31
32 public static bool operator == (AutomatonTransition rv, AutomatonTransition lv) {
33 return rv.Equals(lv);
34 }
35
36 public static bool operator !=(AutomatonTransition rv, AutomatonTransition lv) {
37 return rv.Equals(lv);
38 }
31 }
39 }
32 }
40 }
33
41
@@ -1,348 +1,348
1 using Implab;
1 using Implab;
2 using System;
2 using System;
3 using System.Collections.Generic;
3 using System.Collections.Generic;
4 using System.Linq;
4 using System.Linq;
5 using System.Diagnostics;
5 using System.Diagnostics;
6 using System.IO;
6 using System.IO;
7 using System.CodeDom.Compiler;
7 using System.CodeDom.Compiler;
8 using System.CodeDom;
8 using System.CodeDom;
9
9
10 namespace Implab.Automaton {
10 namespace Implab.Automaton {
11 public class DFATable : IDFATableBuilder {
11 public class DFATable : IDFATableBuilder {
12 int m_stateCount;
12 int m_stateCount;
13 int m_symbolCount;
13 int m_symbolCount;
14 int m_initialState;
14 int m_initialState;
15
15
16 readonly HashSet<int> m_finalStates = new HashSet<int>();
16 readonly HashSet<int> m_finalStates = new HashSet<int>();
17 readonly HashSet<AutomatonTransition> m_transitions = new HashSet<AutomatonTransition>();
17 readonly HashSet<AutomatonTransition> m_transitions = new HashSet<AutomatonTransition>();
18
18
19
19
20 #region IDFADefinition implementation
20 #region IDFADefinition implementation
21
21
22 public bool IsFinalState(int s) {
22 public bool IsFinalState(int s) {
23 Safe.ArgumentInRange(s, 0, m_stateCount, "s");
23 Safe.ArgumentInRange(s >= 0 && s < m_stateCount, nameof(s));
24
24
25 return m_finalStates.Contains(s);
25 return m_finalStates.Contains(s);
26 }
26 }
27
27
28 public IEnumerable<int> FinalStates {
28 public IEnumerable<int> FinalStates {
29 get {
29 get {
30 return m_finalStates;
30 return m_finalStates;
31 }
31 }
32 }
32 }
33
33
34 public int StateCount {
34 public int StateCount {
35 get { return m_stateCount; }
35 get { return m_stateCount; }
36 }
36 }
37
37
38 public int AlphabetSize {
38 public int AlphabetSize {
39 get { return m_symbolCount; }
39 get { return m_symbolCount; }
40 }
40 }
41
41
42 public int InitialState {
42 public int InitialState {
43 get { return m_initialState; }
43 get { return m_initialState; }
44 }
44 }
45
45
46 #endregion
46 #endregion
47
47
48 public void SetInitialState(int s) {
48 public void SetInitialState(int s) {
49 Safe.ArgumentAssert(s >= 0, "s");
49 Safe.ArgumentInRange(s >= 0, nameof(s));
50 m_stateCount = Math.Max(m_stateCount, s + 1);
50 m_stateCount = Math.Max(m_stateCount, s + 1);
51 m_initialState = s;
51 m_initialState = s;
52 }
52 }
53
53
54 public void MarkFinalState(int state) {
54 public void MarkFinalState(int state) {
55 m_stateCount = Math.Max(m_stateCount, state + 1);
55 m_stateCount = Math.Max(m_stateCount, state + 1);
56 m_finalStates.Add(state);
56 m_finalStates.Add(state);
57 }
57 }
58
58
59 public void Add(AutomatonTransition item) {
59 public void Add(AutomatonTransition item) {
60 Safe.ArgumentAssert(item.s1 >= 0, "item");
60 Safe.ArgumentAssert(item.s1 >= 0, nameof(item));
61 Safe.ArgumentAssert(item.s2 >= 0, "item");
61 Safe.ArgumentAssert(item.s2 >= 0, nameof(item));
62 Safe.ArgumentAssert(item.edge >= 0, "item");
62 Safe.ArgumentAssert(item.edge >= 0, nameof(item));
63
63
64 m_stateCount = Math.Max(m_stateCount, Math.Max(item.s1, item.s2) + 1);
64 m_stateCount = Math.Max(m_stateCount, Math.Max(item.s1, item.s2) + 1);
65 m_symbolCount = Math.Max(m_symbolCount, item.edge + 1);
65 m_symbolCount = Math.Max(m_symbolCount, item.edge + 1);
66
66
67 m_transitions.Add(item);
67 m_transitions.Add(item);
68 }
68 }
69
69
70 public void Clear() {
70 public void Clear() {
71 m_stateCount = 0;
71 m_stateCount = 0;
72 m_symbolCount = 0;
72 m_symbolCount = 0;
73 m_finalStates.Clear();
73 m_finalStates.Clear();
74 m_transitions.Clear();
74 m_transitions.Clear();
75 }
75 }
76
76
77 public bool Contains(AutomatonTransition item) {
77 public bool Contains(AutomatonTransition item) {
78 return m_transitions.Contains(item);
78 return m_transitions.Contains(item);
79 }
79 }
80
80
81 public void CopyTo(AutomatonTransition[] array, int arrayIndex) {
81 public void CopyTo(AutomatonTransition[] array, int arrayIndex) {
82 m_transitions.CopyTo(array, arrayIndex);
82 m_transitions.CopyTo(array, arrayIndex);
83 }
83 }
84
84
85 public bool Remove(AutomatonTransition item) {
85 public bool Remove(AutomatonTransition item) {
86 return m_transitions.Remove(item);
86 return m_transitions.Remove(item);
87 }
87 }
88
88
89 public int Count {
89 public int Count {
90 get {
90 get {
91 return m_transitions.Count;
91 return m_transitions.Count;
92 }
92 }
93 }
93 }
94
94
95 public bool IsReadOnly {
95 public bool IsReadOnly {
96 get {
96 get {
97 return false;
97 return false;
98 }
98 }
99 }
99 }
100
100
101 public IEnumerator<AutomatonTransition> GetEnumerator() {
101 public IEnumerator<AutomatonTransition> GetEnumerator() {
102 return m_transitions.GetEnumerator();
102 return m_transitions.GetEnumerator();
103 }
103 }
104
104
105 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
105 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
106 return GetEnumerator();
106 return GetEnumerator();
107 }
107 }
108
108
109 public void AddSymbol(int symbol) {
109 public void AddSymbol(int symbol) {
110 Safe.ArgumentAssert(symbol >= 0, "symbol");
110 Safe.ArgumentAssert(symbol >= 0, "symbol");
111 m_symbolCount = Math.Max(symbol + 1, m_symbolCount);
111 m_symbolCount = Math.Max(symbol + 1, m_symbolCount);
112 }
112 }
113
113
114 public int[,] CreateTransitionTable() {
114 public int[,] CreateTransitionTable() {
115 var table = new int[StateCount,AlphabetSize];
115 var table = new int[StateCount,AlphabetSize];
116
116
117 for (int i = 0; i < StateCount; i++)
117 for (int i = 0; i < StateCount; i++)
118 for (int j = 0; j < AlphabetSize; j++)
118 for (int j = 0; j < AlphabetSize; j++)
119 table[i, j] = AutomatonConst.UNREACHABLE_STATE;
119 table[i, j] = AutomatonConst.UnreachableState;
120
120
121 foreach (var t in this)
121 foreach (var t in this)
122 table[t.s1,t.edge] = t.s2;
122 table[t.s1,t.edge] = (byte)t.s2;
123
123
124 return table;
124 return table;
125 }
125 }
126
126
127 public bool[] CreateFinalStateTable() {
127 public bool[] CreateFinalStateTable() {
128 var table = new bool[StateCount];
128 var table = new bool[StateCount];
129
129
130 foreach (var s in FinalStates)
130 foreach (var s in FinalStates)
131 table[s] = true;
131 table[s] = true;
132
132
133 return table;
133 return table;
134 }
134 }
135
135
136 /// <summary>Формирует множества конечных состояний перед началом работы алгоритма минимизации.</summary>
136 /// <summary>Формирует множества конечных состояний перед началом работы алгоритма минимизации.</summary>
137 /// <remarks>
137 /// <remarks>
138 /// В процессе построения минимального автомата требуется разделить множество состояний,
138 /// В процессе построения минимального автомата требуется разделить множество состояний,
139 /// на два подмножества - конечные состояния и все остальные, после чего эти подмножества
139 /// на два подмножества - конечные состояния и все остальные, после чего эти подмножества
140 /// будут резделены на более мелкие. Иногда требуется гарантировать различия конечных сосотяний,
140 /// будут резделены на более мелкие. Иногда требуется гарантировать различия конечных сосотяний,
141 /// для этого необходимо переопределить даннцю фукнцию, для получения множеств конечных состояний.
141 /// для этого необходимо переопределить даннцю фукнцию, для получения множеств конечных состояний.
142 /// </remarks>
142 /// </remarks>
143 /// <returns>The final states.</returns>
143 /// <returns>The final states.</returns>
144 protected virtual IEnumerable<HashSet<int>> SplitFinalStates(IEnumerable<int> states) {
144 protected virtual IEnumerable<HashSet<int>> SplitFinalStates(IEnumerable<int> states) {
145 return new [] { new HashSet<int>(states) };
145 return new [] { new HashSet<int>(states) };
146 }
146 }
147
147
148 protected void Optimize(
148 protected void Optimize(
149 IDFATableBuilder optimalDFA,
149 IDFATableBuilder optimalDFA,
150 IDictionary<int,int> alphabetMap,
150 IDictionary<int,int> alphabetMap,
151 IDictionary<int,int> stateMap
151 IDictionary<int,int> stateMap
152 ) {
152 ) {
153 Safe.ArgumentNotNull(optimalDFA, "dfa");
153 Safe.ArgumentNotNull(optimalDFA, "dfa");
154 Safe.ArgumentNotNull(alphabetMap, "alphabetMap");
154 Safe.ArgumentNotNull(alphabetMap, "alphabetMap");
155 Safe.ArgumentNotNull(stateMap, "stateMap");
155 Safe.ArgumentNotNull(stateMap, "stateMap");
156
156
157
157
158 var setComparer = new CustomEqualityComparer<HashSet<int>>(
158 var setComparer = new CustomEqualityComparer<HashSet<int>>(
159 (x, y) => x.SetEquals(y),
159 (x, y) => x.SetEquals(y),
160 s => s.Sum(x => x.GetHashCode())
160 s => s.Sum(x => x.GetHashCode())
161 );
161 );
162
162
163 var optimalStates = new HashSet<HashSet<int>>(setComparer);
163 var optimalStates = new HashSet<HashSet<int>>(setComparer);
164 var queue = new HashSet<HashSet<int>>(setComparer);
164 var queue = new HashSet<HashSet<int>>(setComparer);
165
165
166 optimalStates.Add(new HashSet<int>(FinalStates));
166 optimalStates.Add(new HashSet<int>(FinalStates));
167
167
168 var state = new HashSet<int>(
168 var state = new HashSet<int>(
169 Enumerable
169 Enumerable
170 .Range(0, m_stateCount)
170 .Range(0, m_stateCount)
171 .Where(i => !m_finalStates.Contains(i))
171 .Where(i => !m_finalStates.Contains(i))
172 );
172 );
173
173
174 optimalStates.Add(state);
174 optimalStates.Add(state);
175 queue.Add(state);
175 queue.Add(state);
176
176
177 var rmap = m_transitions
177 var rmap = m_transitions
178 .GroupBy(t => t.s2)
178 .GroupBy(t => t.s2)
179 .ToDictionary(
179 .ToDictionary(
180 g => g.Key, // s2
180 g => g.Key, // s2
181 g => g.ToLookup(t => t.edge, t => t.s1)//.ToDictionary(p => p.Key)
181 g => g.ToLookup(t => t.edge, t => t.s1)//.ToDictionary(p => p.Key)
182 );
182 );
183
183
184 while (queue.Count > 0) {
184 while (queue.Count > 0) {
185 var stateA = queue.First();
185 var stateA = queue.First();
186 queue.Remove(stateA);
186 queue.Remove(stateA);
187
187
188 for (int c = 0; c < m_symbolCount; c++) {
188 for (int c = 0; c < m_symbolCount; c++) {
189 var stateX = new HashSet<int>();
189 var stateX = new HashSet<int>();
190 foreach(var a in stateA.Where(rmap.ContainsKey))
190 foreach(var a in stateA.Where(rmap.ContainsKey))
191 stateX.UnionWith(rmap[a][c]); // all states from wich the symbol 'c' leads to the state 'a'
191 stateX.UnionWith(rmap[a][c]); // all states from wich the symbol 'c' leads to the state 'a'
192
192
193 var tmp = optimalStates.ToArray();
193 var tmp = optimalStates.ToArray();
194 foreach (var stateY in tmp) {
194 foreach (var stateY in tmp) {
195 var stateR1 = new HashSet<int>(stateY);
195 var stateR1 = new HashSet<int>(stateY);
196 var stateR2 = new HashSet<int>(stateY);
196 var stateR2 = new HashSet<int>(stateY);
197
197
198 stateR1.IntersectWith(stateX);
198 stateR1.IntersectWith(stateX);
199 stateR2.ExceptWith(stateX);
199 stateR2.ExceptWith(stateX);
200
200
201 if (stateR1.Count > 0 && stateR2.Count > 0) {
201 if (stateR1.Count > 0 && stateR2.Count > 0) {
202
202
203
203
204 optimalStates.Remove(stateY);
204 optimalStates.Remove(stateY);
205 optimalStates.Add(stateR1);
205 optimalStates.Add(stateR1);
206 optimalStates.Add(stateR2);
206 optimalStates.Add(stateR2);
207
207
208 if (queue.Contains(stateY)) {
208 if (queue.Contains(stateY)) {
209 queue.Remove(stateY);
209 queue.Remove(stateY);
210 queue.Add(stateR1);
210 queue.Add(stateR1);
211 queue.Add(stateR2);
211 queue.Add(stateR2);
212 } else {
212 } else {
213 queue.Add(stateR1.Count <= stateR2.Count ? stateR1 : stateR2);
213 queue.Add(stateR1.Count <= stateR2.Count ? stateR1 : stateR2);
214 }
214 }
215 }
215 }
216 }
216 }
217 }
217 }
218 }
218 }
219
219
220 // дополнительно разбиваем конечные состояния
220 // дополнительно разбиваем конечные состояния
221 foreach (var final in optimalStates.Where(s => s.Overlaps(m_finalStates)).ToArray()) {
221 foreach (var final in optimalStates.Where(s => s.Overlaps(m_finalStates)).ToArray()) {
222 optimalStates.Remove(final);
222 optimalStates.Remove(final);
223 foreach (var split in SplitFinalStates(final))
223 foreach (var split in SplitFinalStates(final))
224 optimalStates.Add(split);
224 optimalStates.Add(split);
225 }
225 }
226
226
227
227
228 // карта получения оптимального состояния по соотвествующему ему простому состоянию
228 // карта получения оптимального состояния по соотвествующему ему простому состоянию
229 var nextState = 0;
229 var nextState = 0;
230 foreach (var item in optimalStates) {
230 foreach (var item in optimalStates) {
231 var id = nextState++;
231 var id = nextState++;
232 foreach (var s in item)
232 foreach (var s in item)
233 stateMap[s] = id;
233 stateMap[s] = id;
234 }
234 }
235
235
236 // получаем минимальный алфавит
236 // получаем минимальный алфавит
237 // входные символы не различимы, если Move(s,a1) == Move(s,a2), для любого s
237 // входные символы не различимы, если Move(s,a1) == Move(s,a2), для любого s
238 // для этого используем алгоритм кластеризации, сначала
238 // для этого используем алгоритм кластеризации, сначала
239 // считаем, что все символы не различимы
239 // считаем, что все символы не различимы
240
240
241 var minClasses = new HashSet<HashSet<int>>(setComparer);
241 var minClasses = new HashSet<HashSet<int>>(setComparer);
242 var alphaQueue = new Queue<HashSet<int>>();
242 var alphaQueue = new Queue<HashSet<int>>();
243 alphaQueue.Enqueue(new HashSet<int>(Enumerable.Range(0,AlphabetSize)));
243 alphaQueue.Enqueue(new HashSet<int>(Enumerable.Range(0,AlphabetSize)));
244
244
245 // для всех состояний, будем проверять каждый класс на различимость,
245 // для всех состояний, будем проверять каждый класс на различимость,
246 // т.е. символы различимы, если они приводят к разным состояниям
246 // т.е. символы различимы, если они приводят к разным состояниям
247 for (int s = 0 ; s < optimalStates.Count; s++) {
247 for (int s = 0 ; s < optimalStates.Count; s++) {
248 var newQueue = new Queue<HashSet<int>>();
248 var newQueue = new Queue<HashSet<int>>();
249
249
250 foreach (var A in alphaQueue) {
250 foreach (var A in alphaQueue) {
251 // классы из одного символа делить бесполезно, переводим их сразу в
251 // классы из одного символа делить бесполезно, переводим их сразу в
252 // результирующий алфавит
252 // результирующий алфавит
253 if (A.Count == 1) {
253 if (A.Count == 1) {
254 minClasses.Add(A);
254 minClasses.Add(A);
255 continue;
255 continue;
256 }
256 }
257
257
258 // различаем классы символов, которые переводят в различные оптимальные состояния
258 // различаем классы символов, которые переводят в различные оптимальные состояния
259 // optimalState -> alphaClass
259 // optimalState -> alphaClass
260 var classes = new Dictionary<int, HashSet<int>>();
260 var classes = new Dictionary<int, HashSet<int>>();
261
261
262 foreach (var term in A) {
262 foreach (var term in A) {
263 // ищем все переходы класса по символу term
263 // ищем все переходы класса по символу term
264 var s2 = m_transitions.Where(t => stateMap[t.s1] == s && t.edge == term).Select(t => stateMap[t.s2]).DefaultIfEmpty(-1).First();
264 var s2 = m_transitions.Where(t => stateMap[t.s1] == s && t.edge == term).Select(t => stateMap[t.s2]).DefaultIfEmpty(-1).First();
265
265
266 HashSet<int> a2;
266 HashSet<int> a2;
267 if (!classes.TryGetValue(s2, out a2)) {
267 if (!classes.TryGetValue(s2, out a2)) {
268 a2 = new HashSet<int>();
268 a2 = new HashSet<int>();
269 newQueue.Enqueue(a2);
269 newQueue.Enqueue(a2);
270 classes[s2] = a2;
270 classes[s2] = a2;
271 }
271 }
272 a2.Add(term);
272 a2.Add(term);
273 }
273 }
274 }
274 }
275
275
276 if (newQueue.Count == 0)
276 if (newQueue.Count == 0)
277 break;
277 break;
278 alphaQueue = newQueue;
278 alphaQueue = newQueue;
279 }
279 }
280
280
281 // после окончания работы алгоритма в очереди останутся минимальные различимые классы
281 // после окончания работы алгоритма в очереди останутся минимальные различимые классы
282 // входных символов
282 // входных символов
283 foreach (var A in alphaQueue)
283 foreach (var A in alphaQueue)
284 minClasses.Add(A);
284 minClasses.Add(A);
285
285
286 // построение отображения алфавитов входных символов.
286 // построение отображения алфавитов входных символов.
287 // поскольку символ DFAConst.UNCLASSIFIED_INPUT может иметь
287 // поскольку символ DFAConst.UNCLASSIFIED_INPUT может иметь
288 // специальное значение, тогда сохраним минимальный класс,
288 // специальное значение, тогда сохраним минимальный класс,
289 // содержащий этот символ на томже месте.
289 // содержащий этот символ на томже месте.
290
290
291 var nextCls = 0;
291 var nextCls = 0;
292 foreach (var item in minClasses) {
292 foreach (var item in minClasses) {
293 if (nextCls == AutomatonConst.UNCLASSIFIED_INPUT)
293 if (nextCls == AutomatonConst.UnclassifiedInput)
294 nextCls++;
294 nextCls++;
295
295
296 // сохраняем DFAConst.UNCLASSIFIED_INPUT
296 // сохраняем DFAConst.UNCLASSIFIED_INPUT
297 var cls = item.Contains(AutomatonConst.UNCLASSIFIED_INPUT) ? AutomatonConst.UNCLASSIFIED_INPUT : nextCls++;
297 var cls = item.Contains(AutomatonConst.UnclassifiedInput) ? AutomatonConst.UnclassifiedInput : nextCls++;
298 optimalDFA.AddSymbol(cls);
298 optimalDFA.AddSymbol(cls);
299
299
300 foreach (var a in item)
300 foreach (var a in item)
301 alphabetMap[a] = cls;
301 alphabetMap[a] = cls;
302 }
302 }
303
303
304 // построение автомата
304 // построение автомата
305 optimalDFA.SetInitialState(stateMap[m_initialState]);
305 optimalDFA.SetInitialState(stateMap[m_initialState]);
306
306
307 foreach (var sf in m_finalStates.Select(s => stateMap[s]).Distinct())
307 foreach (var sf in m_finalStates.Select(s => stateMap[s]).Distinct())
308 optimalDFA.MarkFinalState(sf);
308 optimalDFA.MarkFinalState(sf);
309
309
310 foreach (var t in m_transitions.Select(t => new AutomatonTransition(stateMap[t.s1],stateMap[t.s2],alphabetMap[t.edge])).Distinct())
310 foreach (var t in m_transitions.Select(t => new AutomatonTransition(stateMap[t.s1],stateMap[t.s2],alphabetMap[t.edge])).Distinct())
311 optimalDFA.Add(t);
311 optimalDFA.Add(t);
312 }
312 }
313
313
314 protected string PrintDFA<TInput, TState>(IAlphabet<TInput> inputAlphabet, IAlphabet<TState> stateAlphabet) {
314 /*protected string PrintDFA<TInput, TState>(IAlphabet<TInput> inputAlphabet, IAlphabet<TState> stateAlphabet) {
315 Safe.ArgumentNotNull(inputAlphabet, "inputAlphabet");
315 Safe.ArgumentNotNull(inputAlphabet, "inputAlphabet");
316 Safe.ArgumentNotNull(stateAlphabet, "stateAlphabet");
316 Safe.ArgumentNotNull(stateAlphabet, "stateAlphabet");
317
317
318 var data = new List<string>();
318 var data = new List<string>();
319
319
320 data.Add("digraph dfa {");
320 data.Add("digraph dfa {");
321
321
322 foreach (var final in m_finalStates)
322 foreach (var final in m_finalStates)
323 data.Add(String.Format("{0} [shape=box];",String.Join("", stateAlphabet.GetSymbols(final))));
323 data.Add(String.Format("{0} [shape=box];",String.Join("", stateAlphabet.GetSymbols(final))));
324
324
325 foreach (var t in m_transitions)
325 foreach (var t in m_transitions)
326 data.Add(String.Format(
326 data.Add(String.Format(
327 "{0} -> {2} [label={1}];",
327 "{0} -> {2} [label={1}];",
328 String.Join("", stateAlphabet.GetSymbols(t.s1)),
328 String.Join("", stateAlphabet.GetSymbols(t.s1)),
329 ToLiteral(ToLiteral(String.Join("", t.edge == AutomatonConst.UNCLASSIFIED_INPUT ? new [] { "@" } : inputAlphabet.GetSymbols(t.edge).Select(x => x.ToString())))),
329 ToLiteral(ToLiteral(String.Join("", t.edge == AutomatonConst.UnclassifiedInput ? new [] { "@" } : inputAlphabet.GetSymbols(t.edge).Select(x => x.ToString())))),
330 String.Join("", stateAlphabet.GetSymbols(t.s2))
330 String.Join("", stateAlphabet.GetSymbols(t.s2))
331 ));
331 ));
332 data.Add("}");
332 data.Add("}");
333 return String.Join("\n", data);
333 return String.Join("\n", data);
334 }
334 }
335
335
336 static string ToLiteral(string input)
336 static string ToLiteral(string input)
337 {
337 {
338 using (var writer = new StringWriter())
338 using (var writer = new StringWriter())
339 {
339 {
340 using (var provider = CodeDomProvider.CreateProvider("CSharp"))
340 using (var provider = CodeDomProvider.CreateProvider("CSharp"))
341 {
341 {
342 provider.GenerateCodeFromExpression(new CodePrimitiveExpression(input), writer, null);
342 provider.GenerateCodeFromExpression(new CodePrimitiveExpression(input), writer, null);
343 return writer.ToString();
343 return writer.ToString();
344 }
344 }
345 }
345 }
346 }*/
346 }
347 }
347 }
348 }
348 }
1 NO CONTENT: file renamed from Implab/Automaton/IAlphabet.cs to Implab/src/Automaton/IAlphabet.cs
NO CONTENT: file renamed from Implab/Automaton/IAlphabet.cs to Implab/src/Automaton/IAlphabet.cs
1 NO CONTENT: file renamed from Implab/Automaton/IAlphabetBuilder.cs to Implab/src/Automaton/IAlphabetBuilder.cs
NO CONTENT: file renamed from Implab/Automaton/IAlphabetBuilder.cs to Implab/src/Automaton/IAlphabetBuilder.cs
1 NO CONTENT: file renamed from Implab/Automaton/IDFATable.cs to Implab/src/Automaton/IDFATable.cs
NO CONTENT: file renamed from Implab/Automaton/IDFATable.cs to Implab/src/Automaton/IDFATable.cs
1 NO CONTENT: file renamed from Implab/Automaton/IDFATableBuilder.cs to Implab/src/Automaton/IDFATableBuilder.cs
NO CONTENT: file renamed from Implab/Automaton/IDFATableBuilder.cs to Implab/src/Automaton/IDFATableBuilder.cs
1 NO CONTENT: file renamed from Implab/Automaton/IndexedAlphabetBase.cs to Implab/src/Automaton/IndexedAlphabetBase.cs
NO CONTENT: file renamed from Implab/Automaton/IndexedAlphabetBase.cs to Implab/src/Automaton/IndexedAlphabetBase.cs
@@ -1,84 +1,84
1 using System;
1 using System;
2 using System.Collections.Generic;
2 using System.Collections.Generic;
3 using System.Linq;
3 using System.Linq;
4
4
5 namespace Implab.Automaton {
5 namespace Implab.Automaton {
6 public class MapAlphabet<T> : IAlphabetBuilder<T> {
6 public class MapAlphabet<T> : IAlphabetBuilder<T> {
7 readonly Dictionary<T,int> m_map;
7 readonly Dictionary<T,int> m_map;
8 int m_nextCls;
8 int m_nextCls;
9 readonly bool m_supportUnclassified;
9 readonly bool m_supportUnclassified;
10
10
11 public MapAlphabet(bool supportUnclassified, IEqualityComparer<T> comparer) {
11 public MapAlphabet(bool supportUnclassified, IEqualityComparer<T> comparer) {
12 m_map = comparer != null ? new Dictionary<T, int>(comparer) : new Dictionary<T,int>();
12 m_map = comparer != null ? new Dictionary<T, int>(comparer) : new Dictionary<T,int>();
13 m_supportUnclassified = supportUnclassified;
13 m_supportUnclassified = supportUnclassified;
14 m_nextCls = supportUnclassified ? 1 : 0;
14 m_nextCls = supportUnclassified ? 1 : 0;
15 }
15 }
16
16
17 #region IAlphabetBuilder implementation
17 #region IAlphabetBuilder implementation
18
18
19 public int DefineSymbol(T symbol) {
19 public int DefineSymbol(T symbol) {
20 int cls;
20 int cls;
21 return m_map.TryGetValue(symbol, out cls) ? cls : DefineSymbol(symbol, m_nextCls);
21 return m_map.TryGetValue(symbol, out cls) ? cls : DefineSymbol(symbol, m_nextCls);
22 }
22 }
23
23
24 public int DefineSymbol(T symbol, int cls) {
24 public int DefineSymbol(T symbol, int cls) {
25 Safe.ArgumentAssert(cls >= 0, "cls");
25 Safe.ArgumentAssert(cls >= 0, "cls");
26
26
27 m_nextCls = Math.Max(cls + 1, m_nextCls);
27 m_nextCls = Math.Max(cls + 1, m_nextCls);
28 m_map.Add(symbol, cls);
28 m_map.Add(symbol, cls);
29 return cls;
29 return cls;
30 }
30 }
31
31
32 public int DefineClass(IEnumerable<T> symbols) {
32 public int DefineClass(IEnumerable<T> symbols) {
33 return DefineClass(symbols, m_nextCls);
33 return DefineClass(symbols, m_nextCls);
34 }
34 }
35
35
36 public int DefineClass(IEnumerable<T> symbols, int cls) {
36 public int DefineClass(IEnumerable<T> symbols, int cls) {
37 Safe.ArgumentAssert(cls >= 0, "cls");
37 Safe.ArgumentAssert(cls >= 0, "cls");
38 Safe.ArgumentNotNull(symbols, "symbols");
38 Safe.ArgumentNotNull(symbols, "symbols");
39
39
40 m_nextCls = Math.Max(cls + 1, m_nextCls);
40 m_nextCls = Math.Max(cls + 1, m_nextCls);
41
41
42 foreach (var symbol in symbols)
42 foreach (var symbol in symbols)
43 m_map[symbol] = cls;
43 m_map[symbol] = cls;
44 return cls;
44 return cls;
45 }
45 }
46
46
47 #endregion
47 #endregion
48
48
49 #region IAlphabet implementation
49 #region IAlphabet implementation
50
50
51 public int Translate(T symbol) {
51 public int Translate(T symbol) {
52 int cls;
52 int cls;
53 if (m_map.TryGetValue(symbol, out cls))
53 if (m_map.TryGetValue(symbol, out cls))
54 return cls;
54 return cls;
55 if (!m_supportUnclassified)
55 if (!m_supportUnclassified)
56 throw new ArgumentOutOfRangeException("symbol", "The specified symbol isn't in the alphabet");
56 throw new ArgumentOutOfRangeException("symbol", "The specified symbol isn't in the alphabet");
57 return AutomatonConst.UNCLASSIFIED_INPUT;
57 return AutomatonConst.UnclassifiedInput;
58 }
58 }
59
59
60 public int Count {
60 public int Count {
61 get {
61 get {
62 return m_nextCls;
62 return m_nextCls;
63 }
63 }
64 }
64 }
65
65
66 public bool Contains(T symbol) {
66 public bool Contains(T symbol) {
67 return m_supportUnclassified || m_map.ContainsKey(symbol);
67 return m_supportUnclassified || m_map.ContainsKey(symbol);
68 }
68 }
69
69
70
70
71 public IEnumerable<T> GetSymbols(int cls) {
71 public IEnumerable<T> GetSymbols(int cls) {
72 Safe.ArgumentAssert(!m_supportUnclassified || cls > 0, "cls");
72 Safe.ArgumentAssert(!m_supportUnclassified || cls > 0, "cls");
73 return m_map.Where(p => p.Value == cls).Select(p => p.Key);
73 return m_map.Where(p => p.Value == cls).Select(p => p.Key);
74 }
74 }
75 #endregion
75 #endregion
76
76
77 public IEnumerable<KeyValuePair<T,int>> Mappings {
77 public IEnumerable<KeyValuePair<T,int>> Mappings {
78 get {
78 get {
79 return m_map;
79 return m_map;
80 }
80 }
81 }
81 }
82 }
82 }
83 }
83 }
84
84
1 NO CONTENT: file renamed from Implab/Automaton/ParserException.cs to Implab/src/Automaton/ParserException.cs
NO CONTENT: file renamed from Implab/Automaton/ParserException.cs to Implab/src/Automaton/ParserException.cs
1 NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/AltToken.cs to Implab/src/Automaton/RegularExpressions/AltToken.cs
NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/AltToken.cs to Implab/src/Automaton/RegularExpressions/AltToken.cs
1 NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/BinaryToken.cs to Implab/src/Automaton/RegularExpressions/BinaryToken.cs
NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/BinaryToken.cs to Implab/src/Automaton/RegularExpressions/BinaryToken.cs
1 NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/CatToken.cs to Implab/src/Automaton/RegularExpressions/CatToken.cs
NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/CatToken.cs to Implab/src/Automaton/RegularExpressions/CatToken.cs
1 NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/EmptyToken.cs to Implab/src/Automaton/RegularExpressions/EmptyToken.cs
NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/EmptyToken.cs to Implab/src/Automaton/RegularExpressions/EmptyToken.cs
1 NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/EndToken.cs to Implab/src/Automaton/RegularExpressions/EndToken.cs
NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/EndToken.cs to Implab/src/Automaton/RegularExpressions/EndToken.cs
1 NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/EndTokenT.cs to Implab/src/Automaton/RegularExpressions/EndTokenT.cs
NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/EndTokenT.cs to Implab/src/Automaton/RegularExpressions/EndTokenT.cs
1 NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/ITaggedDFABuilder.cs to Implab/src/Automaton/RegularExpressions/ITaggedDFABuilder.cs
NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/ITaggedDFABuilder.cs to Implab/src/Automaton/RegularExpressions/ITaggedDFABuilder.cs
1 NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/IVisitor.cs to Implab/src/Automaton/RegularExpressions/IVisitor.cs
NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/IVisitor.cs to Implab/src/Automaton/RegularExpressions/IVisitor.cs
1 NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/RegularDFA.cs to Implab/src/Automaton/RegularExpressions/RegularDFA.cs
NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/RegularDFA.cs to Implab/src/Automaton/RegularExpressions/RegularDFA.cs
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/RegularExpressionVisitor.cs to Implab/src/Automaton/RegularExpressions/RegularExpressionVisitor.cs
NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/RegularExpressionVisitor.cs to Implab/src/Automaton/RegularExpressions/RegularExpressionVisitor.cs
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/RegularExpressionVisitorT.cs to Implab/src/Automaton/RegularExpressions/RegularExpressionVisitorT.cs
NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/RegularExpressionVisitorT.cs to Implab/src/Automaton/RegularExpressions/RegularExpressionVisitorT.cs
1 NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/StarToken.cs to Implab/src/Automaton/RegularExpressions/StarToken.cs
NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/StarToken.cs to Implab/src/Automaton/RegularExpressions/StarToken.cs
1 NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/SymbolToken.cs to Implab/src/Automaton/RegularExpressions/SymbolToken.cs
NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/SymbolToken.cs to Implab/src/Automaton/RegularExpressions/SymbolToken.cs
1 NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/Token.cs to Implab/src/Automaton/RegularExpressions/Token.cs
NO CONTENT: file renamed from Implab/Automaton/RegularExpressions/Token.cs to Implab/src/Automaton/RegularExpressions/Token.cs
1 NO CONTENT: file renamed from Implab/Components/Disposable.cs to Implab/src/Components/Disposable.cs
NO CONTENT: file renamed from Implab/Components/Disposable.cs to Implab/src/Components/Disposable.cs
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from Implab/Components/DisposablePool.cs to Implab/src/Components/DisposablePool.cs
NO CONTENT: file renamed from Implab/Components/DisposablePool.cs to Implab/src/Components/DisposablePool.cs
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from Implab/Components/ExecutionState.cs to Implab/src/Components/ExecutionState.cs
NO CONTENT: file renamed from Implab/Components/ExecutionState.cs to Implab/src/Components/ExecutionState.cs
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from Implab/Components/IFactory.cs to Implab/src/Components/IFactory.cs
NO CONTENT: file renamed from Implab/Components/IFactory.cs to Implab/src/Components/IFactory.cs
1 NO CONTENT: file renamed from Implab/Components/IInitializable.cs to Implab/src/Components/IInitializable.cs
NO CONTENT: file renamed from Implab/Components/IInitializable.cs to Implab/src/Components/IInitializable.cs
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from Implab/Components/IRunnable.cs to Implab/src/Components/IRunnable.cs
NO CONTENT: file renamed from Implab/Components/IRunnable.cs to Implab/src/Components/IRunnable.cs
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from Implab/Components/LazyAndWeak.cs to Implab/src/Components/LazyAndWeak.cs
NO CONTENT: file renamed from Implab/Components/LazyAndWeak.cs to Implab/src/Components/LazyAndWeak.cs
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from Implab/Components/ObjectPool.cs to Implab/src/Components/ObjectPool.cs
NO CONTENT: file renamed from Implab/Components/ObjectPool.cs to Implab/src/Components/ObjectPool.cs
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from Implab/Components/ServiceLocator.cs to Implab/src/Components/ServiceLocator.cs
NO CONTENT: file renamed from Implab/Components/ServiceLocator.cs to Implab/src/Components/ServiceLocator.cs
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from Implab/CustomEqualityComparer.cs to Implab/src/CustomEqualityComparer.cs
NO CONTENT: file renamed from Implab/CustomEqualityComparer.cs to Implab/src/CustomEqualityComparer.cs
1 NO CONTENT: file renamed from Implab/Formats/ByteAlphabet.cs to Implab/src/Formats/ByteAlphabet.cs
NO CONTENT: file renamed from Implab/Formats/ByteAlphabet.cs to Implab/src/Formats/ByteAlphabet.cs
1 NO CONTENT: file renamed from Implab/Formats/CharAlphabet.cs to Implab/src/Formats/CharAlphabet.cs
NO CONTENT: file renamed from Implab/Formats/CharAlphabet.cs to Implab/src/Formats/CharAlphabet.cs
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from Implab/Formats/Grammar.cs to Implab/src/Formats/Grammar.cs
NO CONTENT: file renamed from Implab/Formats/Grammar.cs to Implab/src/Formats/Grammar.cs
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from Implab/Formats/JSON/JSONElementContext.cs to Implab/src/Formats/Json/JsonElementContext.cs
NO CONTENT: file renamed from Implab/Formats/JSON/JSONElementContext.cs to Implab/src/Formats/Json/JsonElementContext.cs
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from Implab/Formats/JSON/JSONElementType.cs to Implab/src/Formats/Json/JsonElementType.cs
NO CONTENT: file renamed from Implab/Formats/JSON/JSONElementType.cs to Implab/src/Formats/Json/JsonElementType.cs
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from Implab/Formats/JSON/JSONGrammar.cs to Implab/src/Formats/Json/JsonGrammar.cs
NO CONTENT: file renamed from Implab/Formats/JSON/JSONGrammar.cs to Implab/src/Formats/Json/JsonGrammar.cs
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from Implab/Formats/JSON/JSONParser.cs to Implab/src/Formats/Json/JsonReader.cs
NO CONTENT: file renamed from Implab/Formats/JSON/JSONParser.cs to Implab/src/Formats/Json/JsonReader.cs
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from Implab/Formats/JSON/JSONScanner.cs to Implab/src/Formats/Json/JsonScanner.cs
NO CONTENT: file renamed from Implab/Formats/JSON/JSONScanner.cs to Implab/src/Formats/Json/JsonScanner.cs
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from Implab/Formats/JSON/JsonTokenType.cs to Implab/src/Formats/Json/JsonTokenType.cs
NO CONTENT: file renamed from Implab/Formats/JSON/JsonTokenType.cs to Implab/src/Formats/Json/JsonTokenType.cs
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from Implab/Formats/JSON/JSONWriter.cs to Implab/src/Formats/Json/JsonWriter.cs
NO CONTENT: file renamed from Implab/Formats/JSON/JSONWriter.cs to Implab/src/Formats/Json/JsonWriter.cs
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from Implab/Formats/JSON/StringTranslator.cs to Implab/src/Formats/Json/StringTranslator.cs
NO CONTENT: file renamed from Implab/Formats/JSON/StringTranslator.cs to Implab/src/Formats/Json/StringTranslator.cs
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from Implab/IPromise.cs to Implab/src/IPromise.cs
NO CONTENT: file renamed from Implab/IPromise.cs to Implab/src/IPromise.cs
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from Implab/IPromiseT.cs to Implab/src/IPromiseT.cs
NO CONTENT: file renamed from Implab/IPromiseT.cs to Implab/src/IPromiseT.cs
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from Implab/Parallels/AsyncQueue.cs to Implab/src/Parallels/AsyncQueue.cs
NO CONTENT: file renamed from Implab/Parallels/AsyncQueue.cs to Implab/src/Parallels/AsyncQueue.cs
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from Implab/Parallels/BlockingQueue.cs to Implab/src/Parallels/BlockingQueue.cs
NO CONTENT: file renamed from Implab/Parallels/BlockingQueue.cs to Implab/src/Parallels/BlockingQueue.cs
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from Implab/Parallels/DispatchPool.cs to Implab/src/Parallels/DispatchPool.cs
NO CONTENT: file renamed from Implab/Parallels/DispatchPool.cs to Implab/src/Parallels/DispatchPool.cs
1 NO CONTENT: file renamed from Implab/Parallels/SharedLock.cs to Implab/src/Parallels/SharedLock.cs
NO CONTENT: file renamed from Implab/Parallels/SharedLock.cs to Implab/src/Parallels/SharedLock.cs
1 NO CONTENT: file renamed from Implab/Parallels/Signal.cs to Implab/src/Parallels/Signal.cs
NO CONTENT: file renamed from Implab/Parallels/Signal.cs to Implab/src/Parallels/Signal.cs
1 NO CONTENT: file renamed from Implab/PromiseExtensions.cs to Implab/src/PromiseExtensions.cs
NO CONTENT: file renamed from Implab/PromiseExtensions.cs to Implab/src/PromiseExtensions.cs
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from Implab/PromiseTransientException.cs to Implab/src/PromiseTransientException.cs
NO CONTENT: file renamed from Implab/PromiseTransientException.cs to Implab/src/PromiseTransientException.cs
1 NO CONTENT: file renamed from Implab/Safe.cs to Implab/src/Safe.cs
NO CONTENT: file renamed from Implab/Safe.cs to Implab/src/Safe.cs
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
This diff has been collapsed as it changes many lines, (863 lines changed) Show them Hide them
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed, binary diff hidden
NO CONTENT: file was removed, binary diff hidden
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed, binary diff hidden
NO CONTENT: file was removed, binary diff hidden
1 NO CONTENT: file was removed, binary diff hidden
NO CONTENT: file was removed, binary diff hidden
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed, binary diff hidden
NO CONTENT: file was removed, binary diff hidden
1 NO CONTENT: file was removed, binary diff hidden
NO CONTENT: file was removed, binary diff hidden
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed, binary diff hidden
NO CONTENT: file was removed, binary diff hidden
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed, binary diff hidden
NO CONTENT: file was removed, binary diff hidden
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed, binary diff hidden
NO CONTENT: file was removed, binary diff hidden
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed, binary diff hidden
NO CONTENT: file was removed, binary diff hidden
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed, binary diff hidden
NO CONTENT: file was removed, binary diff hidden
1 NO CONTENT: file was removed, binary diff hidden
NO CONTENT: file was removed, binary diff hidden
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
General Comments 3
Under Review
author

Auto status change to "Under Review"

Approved
author

ok, latest stable version should be in default

note
author

Pull request merged and closed