#nullable enable
using IPA.Config.Stores.Attributes;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IPA.Config.Stores
{
///
/// A class providing an extension for to make it easy to use generated
/// config stores.
///
public static class GeneratedStore
{
///
/// The name of the assembly that internals must be visible to to allow internal protection.
///
public const string AssemblyVisibilityTarget = GeneratedStoreImpl.GeneratedAssemblyName;
///
/// Creates a generated of type , registers it to
/// the object, and returns it. This also forces a synchronous config load via
/// if is .
///
///
///
/// must be a public non- class.
/// It can also be internal, but in that case, then your assembly must have the following attribute
/// to allow the generated code to reference it.
///
/// [assembly: InternalsVisibleTo(IPA.Config.Stores.GeneratedStore.AssemblyVisibilityTarget)]
///
///
///
/// Only fields and properties that are public or protected will be considered, and only properties
/// where both the getter and setter are public or protected are considered. Any fields or properties
/// with an applied to them are also ignored. Having properties be is not strictly
/// necessary, however it allows the generated type to keep track of changes and lock around them so that the config will auto-save.
///
///
/// All of the attributes in the namespace are handled as described by them.
///
///
/// If the declares a public or protected,
/// method Changed(), then that method may be called to artificially signal to the runtime that the content of the object
/// has changed. That method will also be called after the write locks are released when a property is set anywhere in the owning
/// tree. This will only be called on the outermost generated object of the config structure, even if the change being signaled
/// is somewhere deep into the tree.
///
///
/// Similarly, can declare a public or protected,
/// method OnReload(), which will be called on the filesystem reader thread after the object has been repopulated with new data
/// values. It will be called after the write lock for this object is released. This will only be called on the outermost generated
/// object of the config structure.
///
///
/// Similarly, can declare a public or protected,
/// method CopyFrom(ConfigType) (the first parameter is the type it is defined on), which may be called to copy the properties from
/// another object of its type easily, and more importantly, as only one change. Its body will be executed after the values have been copied.
///
///
/// Similarly, can declare a public or protected,
/// method ChangeTransaction() returning , which may be called to get an object representing a transactional
/// change. This may be used to change a lot of properties at once without triggering a save multiple times. Ideally, this is used in a
/// block or declaration. The returned from your implementation will have its
/// called after Changed() is called, but before the write lock is released.
/// Unless you have a very good reason to use the nested , avoid it.
///
///
/// If is marked with , the resulting object will implement
/// . Similarly, if implements ,
/// the resulting object will implement it and notify it too.
///
///
/// the type to wrap
/// the to register to
/// whether to synchronously load the content, or trigger an async load
/// a generated instance of as a special
public static T Generated(this Config cfg, bool loadSync = true) where T : class
{
var ret = GeneratedStoreImpl.Create();
cfg.SetStore(ret as IConfigStore);
if (loadSync)
cfg.LoadSync();
else
cfg.LoadAsync();
return ret;
}
///
/// Creates a generated store outside of the context of the config system.
///
///
/// See for more information about how it behaves.
///
/// the type to wrap
/// a generated instance of implementing functionality described by
///
public static T Create() where T : class
=> GeneratedStoreImpl.Create();
}
}