/// <inheritdoc /> protected override void SerializeInto(SerializeNode node) { foreach (var child in Children) { node.Children.Add(child.Serialize()); } }
/// <summary> Finds the first difference in the two documents. </summary> private static void FindDifference(SerializeNode currentState, SerializeNode originalState, string path) { DidYouKnow.That(currentState.TypeId).Should() .Be(originalState.TypeId); var type = currentState.TypeId; path += "<" + type + ">"; var fullPath = path + ".Data"; DidYouKnow.That(currentState.GetDataOrDefault <string>("Body")).Should() .Be(originalState.GetDataOrDefault <string>("Body")); int max = Math.Min(currentState.Children.Count, originalState.Children.Count); for (int i = 0; i < max; i++) { FindDifference(currentState.Children[i], originalState.Children[i], path + ".[" + i + "]"); } var theFullPath = path + ".Count"; DidYouKnow.That(currentState.Children.Count).Should().Be(originalState.Children.Count); }
/// <summary> /// Populates already <see cref="Construct(SerializeNode)"/>-ed <see cref="SerializeNode"/>s using the available <see cref="Consumers"/>, from the bottom of the graph upwards. /// </summary> /// <param name="startNode"></param> private void Populate(SerializeNode startNode) { if (!populating.Contains(startNode)) { try { populating.Add(startNode); if (dependencyMap.ContainsKey(startNode) && dependencyMap[startNode].Any()) { foreach (var dep in dependencyMap[startNode]) { Populate(dep.EndNode); } //// Populate all remaining dependencies. Consumers.PopulateObject( startNode.Value, dependencyMap[startNode].ToDictionary(d => d.DependencyId, d => d.EndNode.Value)); dependencyMap[startNode].Clear(); } } catch (Exception ex) { throw new SerializationException($"Populating {GetPath(startNode)} failed.", ex); } } }
/// <summary> Serializes the given block into a SerializedNode. </summary> /// <returns> A SerializeNode that represents the contents in the given block. </returns> public SerializeNode Serialize() { var node = new SerializeNode(DescriptorHandle); SerializeInto(node); return(node); }
public SerializeNode SerializeAsNode() { var node = new SerializeNode("temp/document"); node.Children.Add(Root.Serialize()); return(node); }
/// <summary> /// Constructs and populates new <see cref="object"/>s in <see cref="CurrentGraph"/> to match its structure and dependencies. /// </summary> /// <param name="root">The root object in the graph, which is currently being deserialized.</param> /// <returns>The final <see cref="object"/> value stored in the <paramref name="root"/> node.</returns> private object ReadGraph(SerializeNode root) { dependencyMap = new Dictionary <SerializeNode, List <SerializeDependency> >(); constructed = new HashSet <SerializeNode>(); populating = new HashSet <SerializeNode>(); Construct(root); Populate(root); return(root.Value); }
/// <summary> Converts a SerializeNode into an XElement </summary> public static XElement Serialize(SerializeNode node) { var childNodes = node.Children.Select(Serialize); var attributeNodes = node.Attributes.Select(kvp => new XElement(AttributeElementName, new XAttribute(KeyAttributeName, kvp.Key), new XAttribute(ValueAttributeName, kvp.Value))); var root = new XElement(NodeElementName, childNodes, attributeNodes, new XAttribute(TypeIdAttributeName, node.TypeId)); return(root); }
/// <inheritdoc /> public override void Deserialize(SerializationContext context, SerializeNode node) { var originalFirst = FirstBlock; var originalLast = LastBlock; foreach (var nodeChild in node.Children) { var childBlock = context.Deserialize(nodeChild); Append(childBlock); } // remove all blocks that used to exist before foreach (var block in GetBlocksBetweenInclusive(originalFirst, originalLast)) { RemoveBlock(block); } }
/// <summary> /// Adds an <see cref="object"/> and its dependencies to the <see cref="CurrentGraph"/>. /// </summary> /// <param name="value">The <see cref="object"/> to add.</param> /// <returns>The created <see cref="SerializeNode"/> representing <paramref name="value"/>.</returns> private SerializeNode GetNode(object value) { if (value != null && !TypeConfiguration.MatchAny().Match(value?.GetType())) { throw new TypeMatchException(TypeConfiguration.MatchAny(), value?.GetType()); } var existing = CurrentGraph.Nodes.FirstOrDefault(n => object.ReferenceEquals(n.Value, value)); if (existing != null) { //// Existing nodes should be reused. return(existing); } else { var node = new SerializeNode(currentId.ToString(), value); currentId++; //// Adds the newly-created node to the graph. CurrentGraph.AddNode(node); //// Check if dependencies need to be resolved or if the value is native/null. if (value != null && !TypeConfiguration.MatchNative().Match(value.GetType())) { //// Get all of the dependencies as connections (unique for each individual node, so can construct them here). var dependencies = Providers.GetDependencies(value) .Select(p => new SerializeDependency(p.Key, node, GetNode(p.Value))); foreach (var dep in dependencies) { //// Add new dependencies to the graph. CurrentGraph.AddConnection(dep); } } else { node.IsNative = true; } return(node); } }
private SerializeNode ReadNode(JObject node, string[] assemblyNames) { Type type = null; if (node["type"].Type == JTokenType.Object) { type = ResolveType((JObject)node["type"], assemblyNames); } var nodeObj = new SerializeNode((string)node["id"], type); if (node.ContainsKey("value")) { nodeObj.Value = node["value"]; nodeObj.IsNative = true; } else { nodeObj.Value = null; nodeObj.IsNative = false; } return(nodeObj); }
private JObject WriteNode(SerializeNode node, IList <Assembly> assemblies) { JObject typeJson = null; if (node.DesiredType != null) { typeJson = GetType(node.DesiredType, assemblies); } if (node.IsNative) { return(new JObject( new JProperty("id", node.Id), new JProperty("type", typeJson), new JProperty("value", node.Value))); } else { return(new JObject( new JProperty("id", node.Id), new JProperty("type", typeJson))); } }
/// <summary> Converts the XElement into a SerializeNode </summary> public static SerializeNode Deserialize(XElement root) { // ReSharper disable PossibleNullReferenceException var typeId = root.Attribute(TypeIdAttributeName).Value; var node = new SerializeNode(typeId); // recreate each element foreach (var attributeElement in root.Elements(AttributeElementName)) { node.AddData(attributeElement.Attribute(KeyAttributeName).Value, attributeElement.Attribute(ValueAttributeName).Value); } // recreate each block foreach (var childElement in root.Elements(NodeElementName)) { node.Children.Add(Deserialize(childElement)); } return(node); // ReSharper restore PossibleNullReferenceException }
private string GetPath(SerializeNode node) { var path = CurrentGraph.FindPath(CurrentGraph.Nodes[0], node); return($"{{Root}}.{string.Join(".", path.Connections.Select(c => c.DependencyId))}"); }
private static void SerializeWithSaveOptions(SerializeNode serialize, bool testXElement, bool testXDocument) { // Test both options at once as they don't really collide SaveOptions so = SaveOptions.DisableFormatting | SaveOptions.OmitDuplicateNamespaces; XElement root = XElement.Parse("<root xmlns:a='uri'><child xmlns:a='uri'><baby xmlns:a='uri'>text</baby></child></root>"); XElement child = root.Element("child"); XElement baby = child.Element("baby"); XNode text = baby.FirstNode; // Verify that without annotation the output gets indented and the duplicate ns decls are not removed if (testXElement) { Assert.Equal(NormalizeNewLines(serialize(child)), "<child xmlns:a=\"uri\"> <baby xmlns:a=\"uri\">text</baby></child>"); } // Now add annotation to the leaf element node // Even though it's in effect the output should stay the same (as there is only one namespace decl and mixed content). baby.AddAnnotation(so); if (testXElement) { Assert.Equal(serialize(baby), "<baby xmlns:a=\"uri\">text</baby>"); } // Now add annotation to the middle node child.AddAnnotation(so); if (testXElement) { // Verify that the options are applied correctly Assert.Equal(NormalizeNewLines(serialize(child)), "<child xmlns:a=\"uri\"><baby>text</baby></child>"); // Verify that the root node is not affected as we don't look for the annotation among descendants Assert.Equal(NormalizeNewLines(serialize(root)), "<root xmlns:a=\"uri\"> <child xmlns:a=\"uri\"> <baby xmlns:a=\"uri\">text</baby> </child></root>"); } // And now add the annotation to the root and remove it from the child to test that we can correctly skip over a node root.AddAnnotation(so); child.RemoveAnnotations(typeof(SaveOptions)); if (testXElement) { // Verify that the options are still applied to child Assert.Equal(serialize(child), "<child xmlns:a=\"uri\"><baby>text</baby></child>"); // And they should be also applied to the root now Assert.Equal(serialize(root), "<root xmlns:a=\"uri\"><child><baby>text</baby></child></root>"); } // Add a document node above it all to test that it works on non-XElement as well XDocument doc = new XDocument(root); // Add the annotation to the doc and remove it from the root doc.AddAnnotation(so); root.RemoveAnnotations(typeof(SaveOptions)); // Options should still apply to root as well as the doc if (testXElement) { Assert.Equal(serialize(root), "<root xmlns:a=\"uri\"><child><baby>text</baby></child></root>"); } if (testXDocument) { Assert.Equal(serialize(doc), "<root xmlns:a=\"uri\"><child><baby>text</baby></child></root>"); } }
private static void SerializeWithSaveOptions(SerializeNode serialize, bool testXElement, bool testXDocument) { // Test both options at once as they don't really collide SaveOptions so = SaveOptions.DisableFormatting | SaveOptions.OmitDuplicateNamespaces; XElement root = XElement.Parse("<root xmlns:a='uri'><child xmlns:a='uri'><baby xmlns:a='uri'>text</baby></child></root>"); XElement child = root.Element("child"); XElement baby = child.Element("baby"); XNode text = baby.FirstNode; // Verify that without annotation the output gets indented and the duplicate ns decls are not removed if (testXElement) { Assert.Equal("<child xmlns:a=\"uri\"> <baby xmlns:a=\"uri\">text</baby></child>", NormalizeNewLines(serialize(child))); } // Now add annotation to the leaf element node // Even though it's in effect the output should stay the same (as there is only one namespace decl and mixed content). baby.AddAnnotation(so); if (testXElement) { Assert.Equal("<baby xmlns:a=\"uri\">text</baby>", serialize(baby)); } // Now add annotation to the middle node child.AddAnnotation(so); if (testXElement) { // Verify that the options are applied correctly Assert.Equal("<child xmlns:a=\"uri\"><baby>text</baby></child>", NormalizeNewLines(serialize(child))); // Verify that the root node is not affected as we don't look for the annotation among descendants Assert.Equal("<root xmlns:a=\"uri\"> <child xmlns:a=\"uri\"> <baby xmlns:a=\"uri\">text</baby> </child></root>", NormalizeNewLines(serialize(root))); } // And now add the annotation to the root and remove it from the child to test that we can correctly skip over a node root.AddAnnotation(so); child.RemoveAnnotations(typeof(SaveOptions)); if (testXElement) { // Verify that the options are still applied to child Assert.Equal("<child xmlns:a=\"uri\"><baby>text</baby></child>", serialize(child)); // And they should be also applied to the root now Assert.Equal("<root xmlns:a=\"uri\"><child><baby>text</baby></child></root>", serialize(root)); } // Add a document node above it all to test that it works on non-XElement as well XDocument doc = new XDocument(root); // Add the annotation to the doc and remove it from the root doc.AddAnnotation(so); root.RemoveAnnotations(typeof(SaveOptions)); // Options should still apply to root as well as the doc if (testXElement) { Assert.Equal("<root xmlns:a=\"uri\"><child><baby>text</baby></child></root>", serialize(root)); } if (testXDocument) { Assert.Equal("<root xmlns:a=\"uri\"><child><baby>text</baby></child></root>", serialize(doc)); } }
/// <summary> Loads the state from <paramref name="node"/> into the current instance. </summary> /// <param name="context"> The context in which the node is being deserialized. </param> /// <param name="node"> The node that contains the data that should be loaded into this block. </param> public abstract void Deserialize(SerializationContext context, SerializeNode node);
public void OnBeforeSerialize() { // not created if (nodes == null) { return; } var nodeIndexLookup = new Dictionary <Node, int>(); var edgeIndexLookup = new Dictionary <Edge, int>(); for (int i = 0; i < nodes.Count; ++i) { nodeIndexLookup.Add(nodes[i], i); } for (int i = 0; i < edges.Count; ++i) { edgeIndexLookup.Add(edges[i], i); } serializeNodes = new List <SerializeNode>(); foreach (var node in nodes) { var serializeNode = new SerializeNode(); #if UNITY_EDITOR serializeNode.label = node.label; #endif serializeNode.type = 0; if ((node as InputNode) != null) { serializeNode.type = 1; } if ((node as OutputNode) != null) { serializeNode.type = 2; } serializeNode.sum = node.sum; serializeNode.edgeIndices = new List <int>(); foreach (var edge in node.edges) { var index = edgeIndexLookup[edge]; serializeNode.edgeIndices.Add(index); } serializeNodes.Add(serializeNode); } serializeEdges = new List <SerializeEdge>(); foreach (var edge in edges) { var serializeEdge = new SerializeEdge(); #if UNITY_EDITOR serializeEdge.label = edge.label; #endif serializeEdge.srcIndex = nodeIndexLookup[edge.src]; serializeEdge.dstIndex = nodeIndexLookup[edge.dst]; serializeEdge.a = edge.a; serializeEdge.b = edge.b; serializeEdge.c = edge.c; serializeEdges.Add(serializeEdge); } }
/// <summary /> public void SerializeInto(SerializeNode node) { node.AddData("Body", _buffer.GetText()); }
/// <summary /> public void Deserialize(SerializationContext context, SerializeNode node) { var text = node.GetDataOrDefault <string>("Body"); Insert(GetCaretAtStart(), new TextBlockContent(text), autoMerge: false); }
/// <summary> /// Constructs new instances of the object tree starting at the given <see cref="SerializeNode"/>, passing constructor parameters greedily where possible. /// </summary> /// <param name="startNode">The <see cref="SerializeNode"/> to start construction at.</param> private void Construct(SerializeNode startNode) { if (!constructed.Contains(startNode)) { try { if (startNode.IsNative) { //// Test only against native trusted types. if (startNode.DesiredType != null && !TypeConfiguration.MatchNative().Match(startNode.DesiredType)) { throw new TypeMatchException(TypeConfiguration.MatchNative(), startNode.DesiredType?.GetType()); } if (startNode.Value is JToken token) { if (token.Type == JTokenType.Null) { startNode.Value = null; } else { startNode.Value = token.ToObject(startNode.DesiredType); } constructed.Add(startNode); } else { throw new SerializationException("Native object not encapsulated in expected JToken value."); } } else { //// Test only against non-native trusted types. if (!TypeConfiguration.MatchTrusted().Match(startNode.DesiredType)) { throw new TypeMatchException(TypeConfiguration.MatchTrusted(), startNode.DesiredType?.GetType()); } //// Get all dependencies. var dependencies = CurrentGraph.GetConnections(startNode); dependencyMap.Add(startNode, new List <SerializeDependency>(dependencies)); //// Construct an object with non-circular dependencies. object newValue = Constructors.Construct( startNode.DesiredType, dependencies .Where(d => !IsCircular(d)) .ToDictionary( d => d.DependencyId, d => { Construct(d.EndNode); Populate(d.EndNode); return(d.EndNode.Value); }), out var usedKeys); dependencyMap[startNode].RemoveRange( dependencyMap[startNode].ToArray() .Where(d => usedKeys.Contains(d.DependencyId))); startNode.Value = newValue; constructed.Add(startNode); foreach (var dep in dependencyMap[startNode]) { Construct(dep.EndNode); } } } catch (Exception ex) { throw new SerializationException($"Constructing {GetPath(startNode)} failed.", ex); } } }
/// <summary> Saves the state of the current instance into <paramref name="node"/>. </summary> /// <param name="node"> The node into which the state of this block should be stored. </param> protected abstract void SerializeInto(SerializeNode node);