예제 #1
0
        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);
            }
        }
예제 #2
0
        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}");
            }
        }
예제 #3
0
        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);
        }
예제 #4
0
        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);
            }
        }
예제 #5
0
        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);
            }
        }
예제 #6
0
        /// <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();
            }
        }
예제 #7
0
        /// <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);
        }