/// <summary>
        /// Converts a type object into ABSave text.
        /// Including: Assembly Name, Version, Culture, PublicKeyToken
        /// </summary>
        /// <param name="typ">The type to write.</param>
        /// <param name="useSB">Whether we are writing to a StringBuilder or not.</param>
        /// <param name="sb">The StringBuilder to write to - if we're writing to one at all.</param>
        /// <param name="writeToCharArray">Whether we should write to a character array (which will then be returned) - it can do both a StringBuilder and character array at the same time.</param>
        /// <returns></returns>
        public static string SerializeType(Type typ, bool useSB = false, StringBuilder sb = null)
        {
            string ret = "";

            // ======
            // MAKE SURE TO VIEW THE ABSOFTWARE DOCS' SPECIFICATION FOR TYPES, IT WILL HELP MAKE THIS LOGIC MAKE SENSE.
            // ======
            // Work out all of the things we need to
            var name              = typ.Assembly.GetName();
            var publicKeyToken    = name.GetPublicKeyToken();
            var version           = name.Version;
            var hasPublicKeyToken = publicKeyToken != null && publicKeyToken.Length != 0;
            var hasCulture        = name.CultureName != "";
            var hasVersion        = !(version.Major == 1 && version.MajorRevision == 0 && version.Minor == 0 && version.MinorRevision == 0);

            // If we're writing a StringBuilder, we'll put the commas in as we go,
            // otherwise, we'll put them all together at the end.
            // PART 1: Type Name
            ret += ABSaveWriter.WriteString(typ.FullName, false, useSB, sb);

            // PART 2: Assembly Name
            ret += ABSaveWriter.WriteString(ABSaveWriter.WriteCharacter(',', useSB, sb) + name.Name, false, useSB, sb);

            // PART 3: Version
            if (hasVersion)
            {
                ret += SerializeVersion(version, useSB, sb);
            }

            // Even if we don't have a version, we might still have to write a comma if there's anything after this!
            else if (hasCulture || hasPublicKeyToken)
            {
                ret += ABSaveWriter.WriteCharacter(',', useSB, sb);
            }

            // PART 4: Culture
            if (hasCulture)
            {
                ret += ABSaveWriter.WriteString(ABSaveWriter.WriteCharacter(',', useSB, sb) + name.CultureName, false, useSB, sb);
            }
            else if (hasPublicKeyToken)
            {
                ret += ABSaveWriter.WriteCharacter(',', useSB, sb);
            }

            // PART 5: PublicKeyToken
            if (hasPublicKeyToken)
            {
                ret += ABSaveWriter.WriteCharacter(',', useSB, sb) + ABSaveWriter.WriteByteArray(name.GetPublicKeyToken(), useSB, sb);
            }

            return(ret);
        }
        /// <summary>
        /// Serializes an object. The object could be anything.
        /// </summary>
        /// <param name="obj">The object to serialize</param>
        /// <param name="useSB">Whether this will write to a string builder (if true), or return a string (if false).</param>
        /// <param name="sb">The StringBuilder to write to - if <paramref name="useSB"/> is true.</param>
        /// <param name="determinedType">The primitive type which has been decided for it.</param>
        /// <param name="writeNextInstructionSymbol">Whether it will write \u0001 on the start - usually false if it is serializing the first object in a class.</param>
        /// <param name="dnWriteEndLevel">"Do Not Write End Level Symbol" - Marks whether to NOT write \u0005 (if true), commonly used for the last object of all.</param>
        /// <returns>If <paramref name="useSB"/> is false, this method will return the result as a string.</returns>
        public static string Serialize(dynamic obj, ABSaveType type, ABSaveSettings settings, out ABSavePrimitiveType determinedType, bool useSB = false, StringBuilder sb = null, bool writeNextInstructionSymbol = true, bool dnWriteEndLevel = false)
        {
            // This will be what to return if useSB is false.
            string ret;

            // For now, make it so we output "unknown".
            determinedType = ABSavePrimitiveType.Unknown;

            // Check if the object is null... or an IntPtr, write the null symbol - otherwise, we could get a StackOverflowException.
            if (obj == null || obj is IntPtr || obj is UIntPtr)
            {
                return(ABSaveWriter.WriteNullItem(useSB, sb));
            }

            // Remember what type the object is - as well as the TypeCode.
            Type objType = obj.GetType();
            var  tCode   = Type.GetTypeCode(obj.GetType());

            // If the object is a string - write it as a string.
            if (tCode == TypeCode.String)
            {
                ret            = ABSaveWriter.WriteString(obj, writeNextInstructionSymbol, useSB, sb);
                determinedType = ABSavePrimitiveType.String;
            }

            // If the object is a number - write it as a number.
            else if (IsNumericType(tCode))
            {
                ret            = ABSaveWriter.WriteNumerical(obj, tCode, true, useSB, sb);
                determinedType = ABSavePrimitiveType.Number;
            }

            // If the object is an array - serialize it as an array.
            else if (IsArray(objType))
            {
                ret            = SerializeArray(obj, objType, type, settings, useSB, sb, dnWriteEndLevel);
                determinedType = ABSavePrimitiveType.Array;
            }

            // If the object is a dictionary - serialize it as a dictionary.
            else if (IsDictionary(objType))
            {
                ret            = SerializeDictionary(obj, type, settings, useSB, sb, dnWriteEndLevel);
                determinedType = ABSavePrimitiveType.Dictionary;
            }

            // If the object is a boolean - serialize it as a boolean.
            else if (tCode == TypeCode.Boolean)
            {
                ret            = SerializeBool(obj, writeNextInstructionSymbol, useSB, sb);
                determinedType = ABSavePrimitiveType.Boolean;
            }

            // If the object is a DateTime - serialize it as a DateTime.
            else if (tCode == TypeCode.DateTime)
            {
                ret            = SerializeDateTime(obj, useSB, sb);
                determinedType = ABSavePrimitiveType.DateTime;
            }

            // If it's a type, just write it out using the ABSaveWriter (for some reason there is no TypeConverter built-in for a type!)
            else if (obj is Type)
            {
                ret            = SerializeType(obj, useSB, sb);
                determinedType = ABSavePrimitiveType.Type;
            }

            // Otherwise, we'll attempt to find a built-in type converter (to a string)
            else
            {
                // Mark it as an object.
                determinedType = ABSavePrimitiveType.Object;

                // Attempt to get a converter for it.
                var canBeTypeConverted = false;
                var typeConv           = TypeDescriptor.GetConverter(objType);

                // Check if the type converter can actually convert it to a string.
                if (typeConv.IsValid(obj))
                {
                    if (typeConv.CanConvertTo(typeof(string)))
                    {
                        canBeTypeConverted = true;
                    }
                }

                // If it can be type converted, convert it using that, and then write it as a string.
                if (canBeTypeConverted)
                {
                    ret = ABSaveWriter.WriteString(typeConv.ConvertToString(obj), writeNextInstructionSymbol, useSB, sb);
                }

                // Otherwise, if it can't be type converted... Manually convert it.
                else
                {
                    ret = SerializeObject(obj, type, objType, settings, writeNextInstructionSymbol, useSB, sb, dnWriteEndLevel);
                }
            }

            // Return the result from this.
            return(ret);
        }
 /// <summary>
 /// Serializes a boolean.
 /// </summary>
 /// <param name="obj">The object to serialize</param>
 /// <param name="writeNextInstructionSymbol">Whether it will write \u0001 on the start - usually false if it serializing the first object in a class.</param>
 /// <param name="useSB">Whether this will write to a string builder (if true), or return a string (if false).</param>
 /// <param name="sb">The StringBuilder to write to - if <paramref name="useSB"/> is true.</param>
 /// <param name="settings">The settings for how to handle certain parts.</param>
 /// <returns>If <paramref name="useSB"/> is false, this method will return the result as a string.</returns>
 public static string SerializeBool(bool obj, bool writeNextInstructionSymbol = true, bool useSB = false, StringBuilder sb = null)
 {
     // Serialize it (use "T" or "F") and then write it as a string - it will return nothing if it needed to write to a StringBuilder.
     return(ABSaveWriter.WriteString(obj ? "T" : "F", writeNextInstructionSymbol, useSB, sb));
 }