Skip to content

Commit

Permalink
Fix config.Root calculation (#199)
Browse files Browse the repository at this point in the history
* Fix config internal Fallback mutation

* Use fallback values of fallback configs

* Made config fully build on creation, and less mutable

* Config root calculation fix - use Value instead of Root from children

* Refactoring

* Added a comment
  • Loading branch information
IgorFedchenko authored and Aaronontheweb committed Jan 24, 2020
1 parent 506c709 commit cabbdde
Showing 1 changed file with 40 additions and 33 deletions.
73 changes: 40 additions & 33 deletions src/Hocon.Configuration/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,41 @@ namespace Hocon
/// </summary>
public class Config : HoconRoot
{
[Obsolete("For json serialization/deserialization only", true)]
private Config()
{
}

/// <inheritdoc />
/// <summary>
/// Initializes a new instance of the <see cref="Config" /> class.
/// </summary>
private Config()
private Config(HoconValue value, Config fallback)
{
Fallback = fallback;
Value = value;

Root = GetRootValue();
}

/// <inheritdoc cref="Config()" />
/// <inheritdoc cref="Config(HoconValue, Config)" />
/// <param name="root">The root node to base this configuration.</param>
/// <exception cref="T:System.ArgumentNullException">"The root value cannot be null."</exception>
public Config(HoconRoot root) : base(root?.Value, root?.Substitutions ?? Enumerable.Empty<HoconSubstitution>())
{
Root = GetRootValue();
}

/// <inheritdoc cref="Config()" />
/// <inheritdoc cref="Config(HoconValue, Config)" />
/// <param name="source">The configuration to use as the primary source.</param>
/// <param name="fallback">The configuration to use as a secondary source.</param>
/// <exception cref="ArgumentNullException">The source configuration cannot be null.</exception>
public Config(HoconRoot source, Config fallback) : base(source?.Value,
source?.Substitutions ?? Enumerable.Empty<HoconSubstitution>())
{
Fallback = fallback;

Root = GetRootValue();
}

/// <summary>
Expand All @@ -54,27 +66,12 @@ public Config(HoconRoot source, Config fallback) : base(source?.Value,
/// <summary>
/// The configuration used as a secondary source.
/// </summary>
public Config Fallback { get; private set; }
public Config Fallback { get; }

/// <summary>
/// The root node of this configuration section
/// </summary>
public virtual HoconValue Root
{
get
{
var elements = new List<IHoconElement>();
for (var config = this; config != null; config = config.Fallback?.Copy())
{
elements.AddRange(config.Value);
}

var aggregated = new HoconValue(null);
aggregated.AddRange(elements.AsEnumerable().Reverse());

return aggregated;
}
}
public virtual HoconValue Root { get; }

/// <summary>
/// Returns string representation of <see cref="Config" />, allowing to include fallback values
Expand All @@ -95,11 +92,7 @@ public string ToString(bool useFallbackValues)
protected Config Copy()
{
//deep clone
return new Config
{
Fallback = Fallback?.Copy(),
Value = (HoconValue) Value.Clone(null)
};
return new Config((HoconValue) Value.Clone(null), Fallback?.Copy());
}

protected override HoconValue GetNode(HoconPath path, bool throwIfNotFound = false)
Expand Down Expand Up @@ -144,14 +137,10 @@ public virtual Config WithFallback(Config fallback)
{
if (fallback == this)
throw new ArgumentException("Config can not have itself as fallback", nameof(fallback));

var clone = Copy();

var current = clone;
while (current.Fallback != null) current = current.Fallback;
current.Fallback = fallback.Copy();

return clone;

// If Fallback is not set - we will set it in new copy
// If Fallback was set - just use it, but with adding new fallback values
return new Config((HoconValue) Value.Clone(null), Fallback?.WithFallback(fallback) ?? fallback);
}

/// <summary>
Expand Down Expand Up @@ -199,6 +188,24 @@ public override IEnumerable<KeyValuePair<string, HoconField>> AsEnumerable()
used.Add(kvp.Key);
}
}

/// <summary>
/// Performs aggregation of Value and all Fallbacks into single <see cref="HoconValue"/> object
/// </summary>
private HoconValue GetRootValue()
{
var elements = new List<IHoconElement>();

for (var config = this; config != null; config = config.Fallback?.Copy())
{
elements.AddRange(config.Value);
}

var aggregated = new HoconValue(null);
aggregated.AddRange(elements.AsEnumerable().Reverse());

return aggregated;
}
}

/// <summary>
Expand Down

0 comments on commit cabbdde

Please sign in to comment.