internal static void SetNodeData(Node node, object data, Type type, FileStyle style) { if (data == null) { throw new Exception("you can't serialize null"); } // ensure the type is initialized. This is especially important if it's added as // a base type in the type's static constructor. System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(type.TypeHandle); string dataAsString = data as string; if (type == typeof(string) && (dataAsString.ContainsNewLine() || node.ChildNodes.Count > 0)) { BaseTypes.SetStringSpecialCase(node, dataAsString, style); } else if (BaseTypes.IsBaseType(type)) { BaseTypes.SetBaseTypeNode(node, data, type, style); } else if (CollectionTypes.TrySetCollection(node, data, type, style)) { return; } else { ComplexTypes.SetComplexNode(node, data, type, style); } }
internal static object GetNodeData(Node node, Type type) { System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(type.TypeHandle); try { if (type == typeof(string) && node.Value == MultiLineStringNode.Terminator && node.ChildLines.Count > 0) { return(BaseTypes.ParseSpecialStringCase(node)); } if (BaseTypes.IsBaseType(type)) { return(BaseTypes.ParseBaseType(node.Value, type)); } var collection = CollectionTypes.TryGetCollection(node, type); if (collection != null) { return(collection); } if (!String.IsNullOrEmpty(node.Value)) { return(ComplexTypeShortcuts.GetFromShortcut(node.Value, type)); } return(ComplexTypes.RetrieveComplexType(node, type)); } catch (Exception e) { throw new Exception($"Error getting data of type {type} from node: {e.InnerException}"); } }
private static Dictionary <TKey, TValue> RetrieveDictionaryGeneric <TKey, TValue>(Node node) { bool keyIsBase = BaseTypes.IsBaseType(typeof(TKey)); var dictionary = new Dictionary <TKey, TValue>(capacity: node.ChildNodes.Count); if (keyIsBase && node.ChildNodeType == NodeChildrenType.key) { foreach (var child in node.ChildNodes) { string childKey = (child as KeyNode).Key; var key = BaseTypes.ParseBaseType <TKey>(childKey); var value = NodeManager.GetNodeData <TValue>(child); dictionary.Add(key, value); } } else { var array = NodeManager.GetNodeData <WritableKeyValuePair <TKey, TValue>[]>(node); foreach (var kvp in array) { dictionary.Add(kvp.key, kvp.value); } } return(dictionary); }
private static void SetDictionaryNodeGeneric <TKey, TValue>(Node node, Dictionary <TKey, TValue> dictionary, FileStyle style, bool forceArrayMode = false) { bool keyIsBase = BaseTypes.IsBaseType(typeof(TKey)); if (keyIsBase && !forceArrayMode && !style.AlwaysArrayDictionaries) { // we might have switched between standard and array dictionary storage, and if so, children need to be reset if (node.ChildNodeType != NodeChildrenType.key) { node.ClearChildren(newChildrenType: NodeChildrenType.key); } var CurrentKeys = new List <string>(capacity: dictionary.Count); foreach (var key in dictionary.Keys) { var value = dictionary[key]; string keyAsText = BaseTypes.SerializeBaseType <TKey>(key, style); if (!Utilities.IsValidKey(keyAsText)) { SetDictionaryNodeGeneric(node, dictionary, style, forceArrayMode: true); return; } CurrentKeys.Add(keyAsText); KeyNode child = node.GetChildAddressedByName(keyAsText); NodeManager.SetNodeData <TValue>(child, value, style); } // make sure that old data in the file is deleted when a new dictionary is saved. // node.ClearChildren() is not used because we want to keep comments and whitespace intact as much as possible. foreach (var key in node.GetChildKeys()) { if (!CurrentKeys.Contains(key)) { node.RemoveChild(key); } } } else // save dictionary as KeyValuePair<TKey, TValue>[] { // we might have switched between standard and array dictionary storage, and if so, children need to be reset if (node.ChildNodeType != NodeChildrenType.list) { node.ClearChildren(newChildrenType: NodeChildrenType.list); } var array = GetWritableKeyValuePairArray(dictionary); NodeManager.SetNodeData(node, array, array.GetType(), style); } }
internal static void SetNodeData(Node node, object data, Type type, FileStyle style) { if (data == null) { node.ClearChildren(); node.Value = Utilities.NullIndicator; return; } else if (node.Value == Utilities.NullIndicator) { node.Value = String.Empty; } // ensure the type is initialized. This is especially important if it's added as // a base type in the type's static constructor. System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(type.TypeHandle); // If we try to save a single-line string and find it is currently saved as a multi-line string, we do NOT remove the mutli-line formatting. // The reason for this is that there might be comments on the """s, and we want to preserve those comments. // Also, this happens in only two cases: // 1. A string that is usually single-line is manually switched to multi-line formatting by a user // 2. A string is saved as multi-line, then later saved as single-line // In case 1, we don't want to piss off the user; keep it how they like it. // In case 2, the string is probably going to be saved again later with multiple lines. It doesn't seem necessary to disrupt the structure // of the file for something temporary. string dataAsString = data as string; if (type == typeof(string) && (dataAsString.ContainsNewLine() || node.ChildNodes.Count > 0)) { BaseTypes.SetStringSpecialCase(node, dataAsString, style); } else if (BaseTypes.IsBaseType(type)) { BaseTypes.SetBaseTypeNode(node, data, type, style); } else if (CollectionTypes.TrySetCollection(node, data, type, style)) { return; } else { ComplexTypes.SetComplexNode(node, data, type, style); } }
/// <summary> Save this file as a dictionary, using the dictionary's keys as top-level keys in the file. </summary> /// <remarks> TKey must be a Base Type </remarks> public void SaveAsDictionary <TKey, TValue>(IDictionary <TKey, TValue> dictionary) { if (!BaseTypes.IsBaseType(typeof(TKey))) { throw new Exception("When using GetAsDictionary, TKey must be a base type"); } bool _autosave = AutoSave; AutoSave = false; // don't write to disk when we don't have to try { var CurrentKeys = new List <string>(capacity: dictionary.Count); foreach (var key in dictionary.Keys) { var keyText = BaseTypes.SerializeBaseType(key, Style); if (!Utilities.IsValidKey(keyText, out string whyNot)) { throw new Exception($"can't save file as this dictionary. A key ({keyText}) is not valid: {whyNot}"); } CurrentKeys.Add(keyText); Set(keyText, dictionary[key]); } // make sure that old data in the file is deleted when a new dictionary is saved. foreach (var key in this.TopLevelKeys) { if (!CurrentKeys.Contains(key)) { this.TopLevelNodes.Remove(key); } } } finally { AutoSave = _autosave; } if (AutoSave) { SaveAllData(); } }
/// <summary> Interpret this file as a dictionary. Top-level keys in the file are interpreted as keys in the dictionary. </summary> /// <remarks> TKey must be a Base Type </remarks> public Dictionary <TKey, TValue> GetAsDictionary <TKey, TValue>() { if (!BaseTypes.IsBaseType(typeof(TKey))) { throw new Exception("When using GetAsDictionary, TKey must be a base type"); } var keys = this.TopLevelKeys; var dictionary = new Dictionary <TKey, TValue>(capacity: keys.Count); foreach (var keyText in keys) { TKey key = BaseTypes.ParseBaseType <TKey>(keyText); TValue value = NodeManager.GetNodeData <TValue>(TopLevelNodes[keyText]); dictionary.Add(key, value); } return(dictionary); }