Example #1
0
 /// <summary>
 ///  Verify the current token is a required value, otherwise throw a good exception.
 /// </summary>
 /// <param name="reader">ITreeReader to check</param>
 /// <param name="expected">Current TreeToken expected</param>
 public static void Expect(this ITreeReader reader, TreeToken expected)
 {
     if (reader.TokenType != expected)
     {
         throw new IOException($"{reader.GetType().Name} expected \"{expected}\" but found \"{reader.TokenType}\" at {reader.Position:n0}");
     }
 }
Example #2
0
        /// <summary>
        ///  ReadObject wraps the loop to read each property in an object and call the corresponding
        ///  setter to set it.
        /// </summary>
        /// <remarks>
        ///  This works for classes only, as the instance can't be passed by ref.
        ///  Structs can serialize as arrays or directly implement the loop to decode themselves.
        ///  Setters take a reference to the instance so that the Dictionary can be static per type,
        ///  which is critical for acceptable performance.
        /// </remarks>
        /// <typeparam name="T">Type being deserialized</typeparam>
        /// <param name="reader">ITreeReader being read from</param>
        /// <param name="instance">T instance being initialized</param>
        /// <param name="setters">Dictionary of setter per field name</param>
        /// <param name="throwOnUnknown">Throw if property name not in setters found</param>
        public static void ReadObject <T>(this ITreeReader reader, T instance, Dictionary <string, Setter <T> > setters, bool throwOnUnknown = true) where T : ITreeSerializable
        {
            // Ensure object state reset before Read
            instance.Clear();

            reader.Expect(TreeToken.StartObject);
            reader.Read();

            while (reader.TokenType == TreeToken.PropertyName)
            {
                string propertyName = reader.ReadAsString();
                reader.Read();

                if (setters.TryGetValue(propertyName, out Setter <T> setter))
                {
                    setter(reader, instance);
                    reader.Read();
                }
                else
                {
                    if (throwOnUnknown)
                    {
                        throw new IOException($"Found unknown {typeof(T).Name} property, \"{propertyName}\", expected one of \"{String.Join("; ", setters.Keys)}\" at {reader.Position:n0} using {reader.GetType().Name}.");
                    }
                    else
                    {
                        reader.Skip();
                    }
                }
            }

            reader.Expect(TreeToken.EndObject);
            // EndObject must be left for caller to handle
        }
Example #3
0
        /// <summary>
        ///  Read existing items in an existing Dictionary instance.
        ///  Used with Dictionaries of specific things which may or may not be present in the file, like Table.Columns.
        /// </summary>
        /// <typeparam name="T">Type of values in Dictionary</typeparam>
        /// <param name="reader">ITreeReader to read from</param>
        /// <param name="dictionary">Dictionary containing items to read</param>
        /// <param name="throwOnUnknown">True to throw for property name not in Dictionary, false to quietly skip over it</param>
        public static void ReadDictionaryItems <T>(this ITreeReader reader, Dictionary <string, T> dictionary, bool throwOnUnknown = true) where T : ITreeSerializable
        {
            reader.Expect(TreeToken.StartObject);
            reader.Read();

            while (reader.TokenType == TreeToken.PropertyName)
            {
                string itemName = reader.ReadAsString();
                reader.Read();

                if (dictionary.TryGetValue(itemName, out T item))
                {
                    item.Read(reader);
                    reader.Read();
                }
                else
                {
                    if (throwOnUnknown)
                    {
                        throw new IOException($"Found unknown {typeof(T).Name} property \"{itemName}\", expected one of \"{String.Join("; ", dictionary.Keys)}\" at {reader.Position:n0} using {reader.GetType().Name}.");
                    }
                    else
                    {
                        reader.Skip();
                    }
                }
            }

            reader.Expect(TreeToken.EndObject);
        }