public static bool TryFindMappingEntry(this ParsingEventBuffer parser, Func <Scalar, bool> selector, out Scalar key, out ParsingEvent value) { parser.Consume <MappingStart>(); do { // so we only want to check keys in this mapping, don't descend switch (parser.Current) { case Scalar scalar: // we've found a scalar, check if it's value matches one // of our predicate var keyMatched = selector(scalar); // move head so we can read or skip value parser.MoveNext(); // read the value of the mapping key if (keyMatched) { // success value = parser.Current; key = scalar; return(true); } // skip the value parser.SkipThisAndNestedEvents(); break; case MappingStart or SequenceStart: parser.SkipThisAndNestedEvents(); break; default: // do nothing, skip to next node parser.MoveNext(); break; } } while (parser.Current is not null); key = null; value = null; return(false); }
public bool Deserialize(IParser reader, Type expectedType, Func <IParser, Type, object> nestedObjectDeserializer, out object value) { // we're essentially "in front of" the normal ObjectNodeDeserializer. // We could let it check if the current event is a mapping, but we also need to know. if (!reader.Accept <MappingStart>(out var mapping)) { value = null; return(false); } // can any of the registered discrimaintors deal with the abstract type? var supportedTypes = typeDiscriminators.Where(t => t.BaseType == expectedType); if (!supportedTypes.Any()) { // no? then not a node/type we want to deal with return(original.Deserialize(reader, expectedType, nestedObjectDeserializer, out value)); } // now buffer all the nodes in this mapping. // it'd be better if we did not have to do this, but YamlDotNet does not support non-streaming access. // See: https://github.com/aaubry/YamlDotNet/issues/343 // WARNING: This has the potential to be quite slow and add a lot of memory usage, especially for large documents. // It's better, if you use this at all, to use it on leaf mappings var start = reader.Current.Start; Type actualType; ParsingEventBuffer buffer; try { buffer = new ParsingEventBuffer(ReadNestedMapping(reader)); // use the discriminators to tell us what type it is really expecting by letting it inspect the parsing events actualType = CheckWithDiscriminators(expectedType, supportedTypes, buffer); } catch (Exception exception) { throw new YamlException(start, reader.Current.End, "Failed when resolving abstract type", exception); } // now continue by re-emitting parsing events buffer.Reset(); return(original.Deserialize(buffer, actualType, nestedObjectDeserializer, out value)); }
private static Type CheckWithDiscriminators(Type expectedType, IEnumerable <ITypeDiscriminator> supportedTypes, ParsingEventBuffer buffer) { foreach (var discriminator in supportedTypes) { buffer.Reset(); if (discriminator.TryResolve(buffer, out var actualType)) { CheckReturnedType(discriminator.BaseType, actualType); return(actualType); } } throw new Exception($"None of the registered type discriminators could supply a child class for {expectedType}"); }