Skip to content

Commit

Permalink
Remove MoreLinq Dependency.
Browse files Browse the repository at this point in the history
  • Loading branch information
HarryCordewener committed Jan 9, 2024
1 parent e0c352b commit 76cab8e
Show file tree
Hide file tree
Showing 8 changed files with 223 additions and 12 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# Change Log
All notable changes to this project will be documented in this file.

## [1.0.5] - 2024-01-09

### Changed
- Removed MoreLinq dependency by making a copy of the function I needed and keep dependencies lower. License retained in the source file - to abide by Apache2 License.

## [1.0.4] - 2024-01-09

### Changed
Expand Down
135 changes: 135 additions & 0 deletions TelnetNegotiationCore/Helpers/AggregateRight.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
#region License and Terms
// This is a direct copy of...
// MoreLINQ - Extensions to LINQ to Objects
// Copyright (c) 2016 Leandro F. Vieira (leandromoh). All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#endregion

namespace LocalMoreLinq
{
using System;
using System.Collections.Generic;
using System.Linq;

static partial class MoreEnumerable
{
/// <summary>
/// Applies a right-associative accumulator function over a sequence.
/// This operator is the right-associative version of the
/// <see cref="Enumerable.Aggregate{TSource}(IEnumerable{TSource}, Func{TSource, TSource, TSource})"/> LINQ operator.
/// </summary>
/// <typeparam name="TSource">The type of the elements of source.</typeparam>
/// <param name="source">Source sequence.</param>
/// <param name="func">A right-associative accumulator function to be invoked on each element.</param>
/// <returns>The final accumulator value.</returns>
/// <example>
/// <code><![CDATA[
/// string result = Enumerable.Range(1, 5).Select(i => i.ToString()).AggregateRight((a, b) => $"({a}/{b})");
/// ]]></code>
/// The <c>result</c> variable will contain <c>"(1/(2/(3/(4/5))))"</c>.
/// </example>
/// <remarks>
/// This operator executes immediately.
/// </remarks>
public static TSource AggregateRight<TSource>(this IEnumerable<TSource> source, Func<TSource, TSource, TSource> func)
{
ArgumentNullException.ThrowIfNull(source);
ArgumentNullException.ThrowIfNull(func);

return source.ToListLike() switch
{
{ Count: 0 } => throw new InvalidOperationException("Sequence contains no elements."),
var list => AggregateRightImplementation(list, list[^1], func, list.Count - 1)
};
}

/// <summary>
/// Applies a right-associative accumulator function over a sequence.
/// The specified seed value is used as the initial accumulator value.
/// This operator is the right-associative version of the
/// <see cref="Enumerable.Aggregate{TSource, TAccumulate}(IEnumerable{TSource}, TAccumulate, Func{TAccumulate, TSource, TAccumulate})"/> LINQ operator.
/// </summary>
/// <typeparam name="TSource">The type of the elements of source.</typeparam>
/// <typeparam name="TAccumulate">The type of the accumulator value.</typeparam>
/// <param name="source">Source sequence.</param>
/// <param name="seed">The initial accumulator value.</param>
/// <param name="func">A right-associative accumulator function to be invoked on each element.</param>
/// <returns>The final accumulator value.</returns>
/// <example>
/// <code><![CDATA[
/// var numbers = Enumerable.Range(1, 5);
/// string result = numbers.AggregateRight("6", (a, b) => $"({a}/{b})");
/// ]]></code>
/// The <c>result</c> variable will contain <c>"(1/(2/(3/(4/(5/6)))))"</c>.
/// </example>
/// <remarks>
/// This operator executes immediately.
/// </remarks>

public static TAccumulate AggregateRight<TSource, TAccumulate>(this IEnumerable<TSource> source, TAccumulate seed, Func<TSource, TAccumulate, TAccumulate> func)
{
ArgumentNullException.ThrowIfNull(source);
ArgumentNullException.ThrowIfNull(func);

var list = source.ToListLike();

return AggregateRightImplementation(list, seed, func, list.Count);
}

/// <summary>
/// Applies a right-associative accumulator function over a sequence.
/// The specified seed value is used as the initial accumulator value,
/// and the specified function is used to select the result value.
/// This operator is the right-associative version of the
/// <see cref="Enumerable.Aggregate{TSource, TAccumulate, TResult}(IEnumerable{TSource}, TAccumulate, Func{TAccumulate, TSource, TAccumulate}, Func{TAccumulate, TResult})"/> LINQ operator.
/// </summary>
/// <typeparam name="TSource">The type of the elements of source.</typeparam>
/// <typeparam name="TAccumulate">The type of the accumulator value.</typeparam>
/// <typeparam name="TResult">The type of the resulting value.</typeparam>
/// <param name="source">Source sequence.</param>
/// <param name="seed">The initial accumulator value.</param>
/// <param name="func">A right-associative accumulator function to be invoked on each element.</param>
/// <param name="resultSelector">A function to transform the final accumulator value into the result value.</param>
/// <returns>The transformed final accumulator value.</returns>
/// <example>
/// <code><![CDATA[
/// var numbers = Enumerable.Range(1, 5);
/// int result = numbers.AggregateRight("6", (a, b) => $"({a}/{b})", str => str.Length);
/// ]]></code>
/// The <c>result</c> variable will contain <c>21</c>.
/// </example>
/// <remarks>
/// This operator executes immediately.
/// </remarks>

public static TResult AggregateRight<TSource, TAccumulate, TResult>(this IEnumerable<TSource> source, TAccumulate seed, Func<TSource, TAccumulate, TAccumulate> func, Func<TAccumulate, TResult> resultSelector)
{
ArgumentNullException.ThrowIfNull(source);
ArgumentNullException.ThrowIfNull(func);
ArgumentNullException.ThrowIfNull(resultSelector);

return resultSelector(source.AggregateRight(seed, func));
}

static TResult AggregateRightImplementation<TSource, TResult>(ListLike<TSource> list, TResult accumulator, Func<TSource, TResult, TResult> func, int i)
{
while (i-- > 0)
{
accumulator = func(list[i], accumulator);
}

return accumulator;
}
}
}
71 changes: 71 additions & 0 deletions TelnetNegotiationCore/Helpers/ListLike.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#region License and Terms
// This is a direct copy of...
// MoreLINQ - Extensions to LINQ to Objects
// Copyright (c) 2018 Atif Aziz. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#endregion

namespace LocalMoreLinq
{
using System;
using System.Collections.Generic;
using System.Linq;

/// <summary>
/// Represents a union over list types implementing either
/// <see cref="IList{T}"/> or <see cref="IReadOnlyList{T}"/>, allowing
/// both to be treated the same.
/// </summary>

readonly struct ListLike<T>
{
readonly IList<T> rw;
readonly IReadOnlyList<T> ro;

public ListLike(IList<T> list)
{
this.rw = list ?? throw new ArgumentNullException(nameof(list));
this.ro = null;
}

public ListLike(IReadOnlyList<T> list)
{
this.rw = null;
this.ro = list ?? throw new ArgumentNullException(nameof(list));
}

public int Count => this.rw?.Count ?? this.ro?.Count ?? 0;

public T this[int index] => this.rw is { } rw ? rw[index]
: this.ro is { } rx ? rx[index]
: throw new ArgumentOutOfRangeException(nameof(index));
}

static class ListLike
{
public static ListLike<T> AsListLike<T>(this List<T> list) => new((IList<T>)list);

public static ListLike<T> ToListLike<T>(this IEnumerable<T> source)
=> source.TryAsListLike() ?? source.ToList().AsListLike();

public static ListLike<T>? TryAsListLike<T>(this IEnumerable<T> source) =>
source switch
{
null => throw new ArgumentNullException(nameof(source)),
IList<T> list => new(list),
IReadOnlyList<T> list => new(list),
_ => null
};
}
}
2 changes: 0 additions & 2 deletions TelnetNegotiationCore/Interpreters/TelnetGMCPInterpreter.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
using Stateless;
using System.Text;
using System.Threading.Tasks;
using System;
using TelnetNegotiationCore.Models;
using System.Collections.Generic;
using OneOf;
using MoreLinq;
using System.Linq;
using System.Text.Json;
using Microsoft.Extensions.Logging;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using MoreLinq;
using OneOf;
using Stateless;
using TelnetNegotiationCore.Models;
Expand Down
17 changes: 10 additions & 7 deletions TelnetNegotiationCore/Interpreters/TelnetSafeInterpreter.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using Stateless;
using System.Collections.Generic;
using System.Linq;
using MoreLinq;
using System;
using TelnetNegotiationCore.Models;
using System.IO;
Expand Down Expand Up @@ -108,9 +107,10 @@ private StateMachine<State, Trigger> SetupSafeNegotiation(StateMachine<State, Tr
var underlyingTriggers = info.States.First(x => (State)x.UnderlyingState == State.SubNegotiation).Transitions
.Select(x => (Trigger)x.Trigger.UnderlyingTrigger);

triggers
.Except(underlyingTriggers)
.ForEach(trigger => tsm.Configure(State.SubNegotiation).Permit(trigger, State.BadSubNegotiation));
foreach(var trigger in triggers.Except(underlyingTriggers))
{
tsm.Configure(State.SubNegotiation).Permit(trigger, State.BadSubNegotiation);
}

TriggerHelper.ForAllTriggersButIAC(t => tsm.Configure(State.BadSubNegotiation).Permit(t, State.BadSubNegotiationEvaluating));
TriggerHelper.ForAllTriggersButIAC(t => tsm.Configure(State.BadSubNegotiationEvaluating).PermitReentry(t));
Expand All @@ -131,12 +131,15 @@ private StateMachine<State, Trigger> SetupSafeNegotiation(StateMachine<State, Tr
var statesAllowingForErrorTransitions = states
.Except(acceptingStateInfo);

statesAllowingForErrorTransitions.ForEach(state => tsm.Configure((State)state.UnderlyingState).Permit(Trigger.Error, State.Accepting));
foreach(var state in statesAllowingForErrorTransitions)
{
tsm.Configure((State)state.UnderlyingState).Permit(Trigger.Error, State.Accepting);
}

tsm.OnUnhandledTrigger(async (state, trigger, unmetguards) =>
tsm.OnUnhandledTrigger(async (state, trigger, unmetGuards) =>
{
_Logger.LogCritical("Bad transition from {@State} with trigger {@Trigger} due to unmet guards: {@UnmetGuards}. Cannot recover. " +
"Ignoring character and attempting to recover.", state, trigger, unmetguards);
"Ignoring character and attempting to recover.", state, trigger, unmetGuards);
await tsm.FireAsync(ParameterizedTrigger(Trigger.Error), Trigger.Error);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
using System.Threading.Tasks;
using Stateless;
using TelnetNegotiationCore.Models;
using MoreLinq;
using OneOf;
using System.Collections.Immutable;
using Microsoft.Extensions.Logging;
using LocalMoreLinq;

namespace TelnetNegotiationCore.Interpreters
{
Expand Down
2 changes: 1 addition & 1 deletion TelnetNegotiationCore/TelnetNegotiationCore.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<LangVersion>latest</LangVersion>
<Version>1.0.4</Version>
<Version>1.0.5</Version>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Title>Telnet Negotiation Core</Title>
<PackageId>$(AssemblyName)</PackageId>
Expand Down

0 comments on commit 76cab8e

Please sign in to comment.