/// <summary>Writes a class instance to the stream.</summary> /// <param name="v">The class instance to write.</param> public void WriteClass(AnyClass?v) { Debug.Assert(InEncapsulation); if (v == null) { WriteSize(0); } else if (_current != null && _format == FormatType.Sliced) { // If writing an instance within a slice and using the sliced format, write an index of that slice's // indirection table. if (_current.IndirectionMap != null && _current.IndirectionMap.TryGetValue(v, out int index)) { // Found, index is position in indirection table + 1 Debug.Assert(index > 0); } else { _current.IndirectionTable ??= new List <AnyClass>(); _current.IndirectionMap ??= new Dictionary <AnyClass, int>(); _current.IndirectionTable.Add(v); index = _current.IndirectionTable.Count; // Position + 1 (0 is reserved for null) _current.IndirectionMap.Add(v, index); } WriteSize(index); } else { WriteInstance(v); // Writes the instance or a reference if already marshaled. } }
public void CheckSUnknown(AnyClass?obj, Current current) { TestHelper.Assert(obj is SUnknown); var su = (SUnknown)obj; TestHelper.Assert(su.Su.Equals("SUnknown.su")); }
/// <summary>Writes a tagged class instance to the stream.</summary> /// <param name="tag">The tag.</param> /// <param name="v">The class instance to write.</param> public void WriteTaggedClass(int tag, AnyClass?v) { if (v != null) { WriteTaggedParamHeader(tag, EncodingDefinitions.TagFormat.Class); WriteClass(v); } }
public ValueTask CheckSUnknownAsync(AnyClass?obj, Current current) { TestHelper.Assert(obj != null); var su = (SUnknown)obj; TestHelper.Assert(su.Su.Equals("SUnknown.su")); return(new ValueTask(Task.CompletedTask)); }
private AnyClass ReadInstance(int index) { Debug.Assert(index > 0); if (index > 1) { if (_instanceMap != null && _instanceMap.Count > index - 2) { return(_instanceMap[index - 2]); } throw new InvalidDataException($"could not find index {index} in {nameof(_instanceMap)}"); } if (++_classGraphDepth > Communicator.ClassGraphDepthMax) { throw new InvalidDataException("maximum class graph depth reached"); } InstanceData?previousCurrent = Push(InstanceType.Class); Debug.Assert(_current != null); AnyClass?instance = null; do { // Read the slice header. string?typeIdOpt = ReadSliceHeaderIntoCurrent(); // We cannot read the indirection table at this point as it may reference the new instance that is // not created yet. IClassFactory?factory = null; if (typeIdOpt is string typeId) { Debug.Assert(_current.SliceCompactId == null); factory = Communicator.FindClassFactory(typeId); } else if (_current.SliceCompactId is int compactId) { factory = Communicator.FindClassFactory(compactId); } if (factory != null) { instance = factory.Read(this); } else if (SkipSlice()) // Slice off what we don't understand. { instance = new UnknownSlicedClass(this); } }while (instance == null); Pop(previousCurrent); --_classGraphDepth; return(instance); }
/// <summary>Writes a tagged class instance to the stream.</summary> /// <param name="tag">The tag.</param> /// <param name="v">The class instance to write.</param> public void WriteTaggedClass(int tag, AnyClass?v) { if (v != null) { WriteTaggedParamHeader(tag, EncodingDefinitions.TagFormat.Class); // Since the recipient may not know the tag, we cannot use formal type optimization and set formalTypeId // to null. WriteClass(v, formalTypeId: null); } }
/// <summary>Writes a class instance to the stream, or null.</summary> /// <param name="v">The class instance to write, or null.</param> /// <param name="formalTypeId">The type ID of the formal type of the parameter or data member being written. /// Use null when the type of the parameter/data member is AnyClass.</param> public void WriteNullableClass(AnyClass?v, string?formalTypeId) { Debug.Assert(InEncapsulation); if (v == null) { WriteSize(0); } else { WriteClass(v, formalTypeId); } }
/// <summary>Writes a class instance to the stream, or null.</summary> /// <param name="v">The class instance to write, or null</param> public void WriteNullableClass(AnyClass?v) { Debug.Assert(InEncapsulation); if (v == null) { WriteSize(0); } else { WriteClass(v); } }
/// <summary>Reads a nullable class instance from the stream.</summary> /// <param name="formalTypeId">The type ID of the formal type of the parameter or data member being read. /// Use null when the type of the parameter/data member is AnyClass.</param> /// <returns>The class instance read from the stream, or null.</returns> public T?ReadNullableClass <T>(string?formalTypeId) where T : AnyClass { AnyClass?obj = ReadAnyClass(formalTypeId); if (obj is T result) { return(result); } else if (obj == null) { return(null); } else { throw new InvalidDataException(@$ "read instance of type `{obj.GetType().FullName }' but expected instance of type `{typeof(T).FullName}'"); } }
/// <summary>Reads a tagged class instance from the stream.</summary> /// <param name="tag">The tag.</param> /// <returns>The class instance, or null.</returns> public T?ReadTaggedClass <T>(int tag) where T : AnyClass { AnyClass?obj = ReadTaggedAnyClass(tag); if (obj is T result) { return(result); } else if (obj == null) { return(null); } else { throw new InvalidDataException(@$ "read instance of type `{obj.GetType().FullName }' but expected instance of type `{typeof(T).FullName}'"); } }
/// <summary>Reads a class instance from the stream.</summary> /// <returns>The class instance, or null.</returns> public T?ReadClass <T>() where T : AnyClass { AnyClass?obj = ReadAnyClass(); if (obj == null) { return(null); } else if (obj is T) { return((T)obj); } else { throw new InvalidDataException(@$ "read instance of type `{obj.GetType().FullName }' but expected instance of type `{typeof(T).FullName}'"); } }
/// <summary>Reads a class instance from the stream.</summary> /// <param name="index">The index of the class instance. If greater than 1, it's a reference to a previously /// seen class; if 1, the class's bytes are next on the stream. Cannot be 0 or less.</param> /// <param name="formalTypeId">The type ID of the formal type of the parameter or data member being read. /// </param> private AnyClass ReadInstance(int index, string?formalTypeId) { Debug.Assert(Communicator != null); Debug.Assert(index > 0); if (index > 1) { if (_instanceMap != null && _instanceMap.Count > index - 2) { return(_instanceMap[index - 2]); } throw new InvalidDataException($"could not find index {index} in {nameof(_instanceMap)}"); } if (++_classGraphDepth > Communicator.ClassGraphMaxDepth) { throw new InvalidDataException("maximum class graph depth reached"); } // Save current in case we're reading a nested instance. InstanceData previousCurrent = _current; _current = default; _current.InstanceType = InstanceType.Class; AnyClass?instance = null; _instanceMap ??= new List <AnyClass>(); if (OldEncoding) { bool readIndirectionTable = true; do { // Read the slice header. (string?typeId, int?compactId) = ReadSliceHeaderIntoCurrent11(); // We cannot read the indirection table at this point as it may reference the new instance that is // not created yet. Func <AnyClass>?factory = null; if (typeId != null) { factory = Communicator.FindClassFactory(typeId); } else if (compactId is int compactIdValue) { factory = Communicator.FindClassFactory(compactIdValue); } if (factory != null) { instance = factory(); } else if (SkipSlice(typeId, compactId)) // Slice off what we don't understand. { instance = new UnknownSlicedClass(); // Don't read the indirection table as it's the last entry in DeferredIndirectionTableList11. readIndirectionTable = false; } }while (instance == null); // Add the instance to the map/list of instances. This must be done before reading the instances (for // circular references). _instanceMap.Add(instance); // Read all the deferred indirection tables now that the instance is inserted in _instanceMap. if (_current.DeferredIndirectionTableList11?.Count > 0) { int savedPos = Pos; Debug.Assert(_current.Slices?.Count == _current.DeferredIndirectionTableList11.Count); for (int i = 0; i < _current.DeferredIndirectionTableList11.Count; ++i) { int pos = _current.DeferredIndirectionTableList11[i]; if (pos > 0) { Pos = pos; _current.Slices[i].Instances = Array.AsReadOnly(ReadIndirectionTable()); } // else remains empty } Pos = savedPos; } if (readIndirectionTable) { ReadIndirectionTableIntoCurrent(); } } else { // With the 2.0 encoding, we don't need a DeferredIndirectionTableList because all the type IDs are // provided by the first slice (when using the sliced format). (string[]? allTypeIds, _, _) = ReadFirstSliceHeaderIntoCurrent20(); if (allTypeIds != null) { int skipCount = 0; foreach (string typeId in allTypeIds) { if (Communicator.FindClassFactory(typeId) is Func <AnyClass> factory) { instance = factory(); break; // foreach } else { skipCount++; } } instance ??= new UnknownSlicedClass(); _instanceMap.Add(instance); ReadIndirectionTableIntoCurrent(); // read the indirection table immediately for (int i = 0; i < skipCount; ++i) { // SkipSlice saves the slice data including the current indirection table, if any. if (SkipSlice(allTypeIds[i])) { if (i != skipCount - 1) { throw new InvalidDataException( "class slice marked as the last slice is not the last slice"); } break; } else { ReadNextSliceHeaderIntoCurrent(); ReadIndirectionTableIntoCurrent(); } } } else if (formalTypeId != null) { // received null and formalTypeId is not null, apply formal type optimization. if (Communicator.FindClassFactory(formalTypeId) is Func <AnyClass> factory) { instance = factory(); _instanceMap.Add(instance); ReadIndirectionTableIntoCurrent(); // Nothing to skip } else { throw new ArgumentException($"cannot find class factory for `{formalTypeId}'", nameof(formalTypeId)); } } else { throw new InvalidDataException( @$ "cannot read a class instance with no type ID; did you forget to specify the { nameof(formalTypeId)}?"); } }
internal static ITestPrx Run(TestHelper helper) { Communicator communicator = helper.Communicator() !; var test = ITestPrx.Parse($"test:{helper.GetTestEndpoint(0)}", communicator); TextWriter output = helper.GetWriter(); output.Write("testing BitSequence and ReadOnlyBitSequence... "); Span <byte> span1 = stackalloc byte[7]; Span <byte> span2 = stackalloc byte[3]; var bitSequence = new BitSequence(span1, span2); TestHelper.Assert(bitSequence.Length == 80); var onBits = new int[] { 0, 9, 35, 69, 70, 71, 79 }; foreach (int i in onBits) { bitSequence[i] = true; } bitSequence[69] = true; // double true for (int i = 0; i < bitSequence.Length; ++i) { TestHelper.Assert(bitSequence[i] == onBits.Contains(i)); bitSequence[i] = !bitSequence[i]; } for (int i = 0; i < bitSequence.Length; ++i) { TestHelper.Assert(bitSequence[i] != onBits.Contains(i)); bitSequence[i] = !bitSequence[i]; // back to original value } try { bitSequence[81] = true; TestHelper.Assert(false); } catch (IndexOutOfRangeException) { // expected } try { bitSequence[-5] = true; TestHelper.Assert(false); } catch (IndexOutOfRangeException) { // expected } Span <byte> span = stackalloc byte[10]; span1.CopyTo(span); span2.CopyTo(span.Slice(7)); var roBitSequence = new ReadOnlyBitSequence(span); TestHelper.Assert(roBitSequence.Length == 80); for (int i = 0; i < roBitSequence.Length; ++i) { TestHelper.Assert(roBitSequence[i] == onBits.Contains(i)); } try { bool _ = roBitSequence[80]; TestHelper.Assert(false); } catch (IndexOutOfRangeException) { // expected } try { bool _ = roBitSequence[-5]; TestHelper.Assert(false); } catch (IndexOutOfRangeException) { // expected } output.Flush(); output.WriteLine("ok"); output.Write("testing basic operations with optional parameters... "); test.OpSingleInInt(null); test.OpSingleInInt(test.OpSingleOutInt()); test.OpSingleInInt(test.OpSingleReturnInt()); test.OpSingleInString(null); test.OpSingleInString(test.OpSingleReturnString()); test.OpBasicIn(17, 17, "test", "test"); test.OpBasicIn(17, 17, null, "test"); test.OpBasicIn(17, null, null, "test"); (int?r, int o1, int?o2, string?o3) = test.OpBasicInOut(5, 15, "test"); TestHelper.Assert(r !.Value == 15 && o1 == 5 && o2 !.Value == 15 && o3 ! == "test"); (r, o1, o2, o3) = test.OpBasicInOut(6, null, null); TestHelper.Assert(r == null && o1 == 6 && o2 == null && o3 == null); output.WriteLine("ok"); output.Write("testing operations with proxies and class parameters... "); TestHelper.Assert(test.OpObject(test, test) !.Equals(test)); TestHelper.Assert(test.OpObject(test, null) == null); TestHelper.Assert(test.OpTest(test, test) !.Equals(test)); TestHelper.Assert(test.OpTest(test, null) == null); var classInstance = new C(42); AnyClass?anyClass = test.OpAnyClass(classInstance, classInstance); TestHelper.Assert(anyClass != null && ((C)anyClass).X == 42); TestHelper.Assert(test.OpAnyClass(classInstance, null) == null); TestHelper.Assert(test.OpC(classInstance, classInstance) !.X == 42); TestHelper.Assert(test.OpC(classInstance, null) == null); try { test.OpObject(null !, null); TestHelper.Assert(false); } catch (NullReferenceException) { } try { test.OpTest(null !, null); TestHelper.Assert(false); } catch (NullReferenceException) { } // We detect null class instances through asserts during marshaling. output.WriteLine("ok"); output.Write("testing operations with sequence<T?> parameters... "); int?[] intSeq = new int?[] { 1, -5, null, 19, -35000 }; TestHelper.Assert(test.OpOptIntSeq(intSeq).SequenceEqual(intSeq)); TestHelper.Assert(test.OpTaggedOptIntSeq(intSeq) !.SequenceEqual(intSeq)); TestHelper.Assert(test.OpTaggedOptIntSeq(null) == null); string?[] stringSeq = new string?[] { "foo", "test", null, "", "bar" }; TestHelper.Assert(test.OpOptStringSeq(stringSeq).SequenceEqual(stringSeq)); TestHelper.Assert(test.OpTaggedOptStringSeq(stringSeq) !.SequenceEqual(stringSeq)); TestHelper.Assert(test.OpTaggedOptStringSeq(null) == null); output.WriteLine("ok"); output.Write("testing operations with dictionary<K, V?> parameters... "); Dictionary <int, int?> intIntDict = new Dictionary <int, int?> { { 1, -5 }, { 3, null }, { 5, 19 }, { 7, -35000 } }; TestHelper.Assert(test.OpIntOptIntDict(intIntDict).DictionaryEqual(intIntDict)); TestHelper.Assert(test.OpTaggedIntOptIntDict(intIntDict) !.DictionaryEqual(intIntDict)); TestHelper.Assert(test.OpTaggedIntOptIntDict(null) == null); Dictionary <int, string?> intStringDict = new Dictionary <int, string?> { { 1, "foo" }, { 3, "test" }, { 5, null }, { 7, "bar" } }; TestHelper.Assert(test.OpIntOptStringDict(intStringDict).DictionaryEqual(intStringDict)); TestHelper.Assert(test.OpTaggedIntOptStringDict(intStringDict) !.DictionaryEqual(intStringDict)); TestHelper.Assert(test.OpTaggedIntOptStringDict(null) == null); output.WriteLine("ok"); return(test); }
internal static ITestPrx Run(TestHelper helper) { Communicator communicator = helper.Communicator !; var test = ITestPrx.Parse(helper.GetTestProxy("test", 0), communicator); TextWriter output = helper.Output; output.Write("testing BitSequence and ReadOnlyBitSequence... "); Span <byte> span1 = stackalloc byte[7]; Span <byte> span2 = stackalloc byte[3]; var bitSequence = new BitSequence(span1, span2); TestHelper.Assert(bitSequence.Length == 80); var onBits = new int[] { 0, 9, 35, 69, 70, 71, 79 }; foreach (int i in onBits) { bitSequence[i] = true; } bitSequence[69] = true; // double true for (int i = 0; i < bitSequence.Length; ++i) { TestHelper.Assert(bitSequence[i] == onBits.Contains(i)); bitSequence[i] = !bitSequence[i]; } for (int i = 0; i < bitSequence.Length; ++i) { TestHelper.Assert(bitSequence[i] != onBits.Contains(i)); bitSequence[i] = !bitSequence[i]; // back to original value } try { bitSequence[81] = true; TestHelper.Assert(false); } catch (IndexOutOfRangeException) { // expected } try { bitSequence[-5] = true; TestHelper.Assert(false); } catch (IndexOutOfRangeException) { // expected } Span <byte> span = stackalloc byte[10]; span1.CopyTo(span); span2.CopyTo(span.Slice(7)); var roBitSequence = new ReadOnlyBitSequence(span); TestHelper.Assert(roBitSequence.Length == 80); for (int i = 0; i < roBitSequence.Length; ++i) { TestHelper.Assert(roBitSequence[i] == onBits.Contains(i)); } try { bool _ = roBitSequence[80]; TestHelper.Assert(false); } catch (IndexOutOfRangeException) { // expected } try { bool _ = roBitSequence[-5]; TestHelper.Assert(false); } catch (IndexOutOfRangeException) { // expected } output.Flush(); output.WriteLine("ok"); output.Write("testing basic operations with optional parameters... "); test.OpInt(null); test.OpInt(test.OpReturnInt()); test.OpString(null); test.OpString(test.OpReturnString()); test.OpBasic(17, 17, "test", "test"); test.OpBasic(17, 17, null, "test"); test.OpBasic(17, null, null, "test"); (int?r, int o1, int?o2, string?o3) = test.OpBasicReturnTuple(5, 15, "test"); TestHelper.Assert(r !.Value == 15 && o1 == 5 && o2 !.Value == 15 && o3 ! == "test"); (r, o1, o2, o3) = test.OpBasicReturnTuple(6, null, null); TestHelper.Assert(r == null && o1 == 6 && o2 == null && o3 == null); output.WriteLine("ok"); output.Write("testing operations with proxies and class parameters... "); TestHelper.Assert(test.OpObject(test, test) !.Equals(test)); TestHelper.Assert(test.OpObject(test, null) == null); TestHelper.Assert(test.OpTest(test, test) !.Equals(test)); TestHelper.Assert(test.OpTest(test, null) == null); var classInstance = new C(42); AnyClass?anyClass = test.OpAnyClass(classInstance, classInstance); TestHelper.Assert(anyClass != null && ((C)anyClass).X == 42); TestHelper.Assert(test.OpAnyClass(classInstance, null) == null); TestHelper.Assert(test.OpC(classInstance, classInstance) !.X == 42); TestHelper.Assert(test.OpC(classInstance, null) == null); try { test.OpObject(null !, null); TestHelper.Assert(false); } catch (NullReferenceException) { } try { test.OpTest(null !, null); TestHelper.Assert(false); } catch (NullReferenceException) { } // We detect null class instances through asserts during marshaling. output.WriteLine("ok"); output.Write("testing operations with sequence<T?> parameters... "); int?[] intSeq = new int?[] { 1, -5, null, 19, -35000 }; TestHelper.Assert(test.OpOptIntSeq(intSeq).SequenceEqual(intSeq)); TestHelper.Assert(test.OpTaggedOptIntSeq(intSeq) !.SequenceEqual(intSeq)); TestHelper.Assert(test.OpTaggedOptIntSeq(null) == null); string?[] stringSeq = new string?[] { "foo", "test", null, "", "bar" }; TestHelper.Assert(test.OpOptStringSeq(stringSeq).SequenceEqual(stringSeq)); TestHelper.Assert(test.OpTaggedOptStringSeq(stringSeq) !.SequenceEqual(stringSeq)); TestHelper.Assert(test.OpTaggedOptStringSeq(null) == null); output.WriteLine("ok"); output.Write("testing operations with dictionary<K, V?> parameters... "); Dictionary <int, int?> intIntDict = new Dictionary <int, int?> { { 1, -5 }, { 3, null }, { 5, 19 }, { 7, -35000 } }; TestHelper.Assert(test.OpIntOptIntDict(intIntDict).DictionaryEquals(intIntDict)); TestHelper.Assert(test.OpTaggedIntOptIntDict(intIntDict) !.DictionaryEquals(intIntDict)); TestHelper.Assert(test.OpTaggedIntOptIntDict(null) == null); Dictionary <int, string?> intStringDict = new Dictionary <int, string?> { { 1, "foo" }, { 3, "test" }, { 5, null }, { 7, "bar" } }; TestHelper.Assert(test.OpIntOptStringDict(intStringDict).DictionaryEquals(intStringDict)); TestHelper.Assert(test.OpTaggedIntOptStringDict(intStringDict) !.DictionaryEquals(intStringDict)); TestHelper.Assert(test.OpTaggedIntOptStringDict(null) == null); output.WriteLine("ok"); output.Write("testing struct with optional data members... "); var myStruct = new MyStruct(test, null, new string?[] { "foo", null, "bar" }); MyStruct myStructResult = test.OpMyStruct(myStruct); TestHelper.Assert(myStruct == myStructResult); myStructResult = test.OpOptMyStruct(myStruct) !.Value; TestHelper.Assert(myStruct == myStructResult); TestHelper.Assert(test.OpOptMyStruct(null) == null); output.WriteLine("ok"); output.Write("testing class with optional data members... "); var derived = new Derived(test, null, new string?[] { "foo", null, "bar" }, null, "test"); Derived derivedResult = test.OpDerived(derived); TestHelper.Assert(derivedResult.Proxy !.Equals(derived.Proxy) && derivedResult.X == derived.X && derivedResult.StringSeq !.SequenceEqual(derived.StringSeq !) && derivedResult.SomeClass == null && derivedResult.S == derived.S); derivedResult = test.OpOptDerived(derived) !; TestHelper.Assert(derivedResult.Proxy !.Equals(derived.Proxy) && derivedResult.X == derived.X && derivedResult.StringSeq !.SequenceEqual(derived.StringSeq) && derivedResult.SomeClass == null && derivedResult.S == derived.S); TestHelper.Assert(test.OpOptDerived(null) == null); output.WriteLine("ok"); output.Write("testing exception with optional data members... "); try { test.OpDerivedEx(); TestHelper.Assert(false); } catch (DerivedEx ex) { TestHelper.Assert(ex.Proxy == null && ex.X == 5 && ex.StringSeq !.SequenceEqual(new string?[] { "foo", null, "bar" }) && ex.SomeClass is C someClass && someClass.X == 42 && ex.S == "test"); } try { test.OpDerivedEx(context: new Dictionary <string, string> { { "all null", "yes" } }); TestHelper.Assert(false); } catch (DerivedEx ex) { TestHelper.Assert(ex.Proxy == null && ex.X == null && ex.StringSeq == null && ex.SomeClass == null && ex.S == null); } output.WriteLine("ok"); return(test); }
public AnyClass?PingPong(AnyClass?obj, Current current) => obj;
public AnyClass?PingPong(AnyClass?obj, Current current, CancellationToken cancel) => obj;
PingPongAsync(AnyClass?obj, Current current) => MakeValueTask(obj);
public (AnyClass?, AnyClass?) opClass(AnyClass?v1, Current current) => (v1, v1);
public ValueTask <AnyClass?> PingPongAsync(AnyClass?obj, Current current, CancellationToken cancel) =>
pingPongAsync(AnyClass?obj, Current current) => FromResult(obj);