Copse.SimpleSerializer
0.3.0-alpha.16
See the version list below for details.
dotnet add package Copse.SimpleSerializer --version 0.3.0-alpha.16
NuGet\Install-Package Copse.SimpleSerializer -Version 0.3.0-alpha.16
<PackageReference Include="Copse.SimpleSerializer" Version="0.3.0-alpha.16" />
<PackageVersion Include="Copse.SimpleSerializer" Version="0.3.0-alpha.16" />
<PackageReference Include="Copse.SimpleSerializer" />
paket add Copse.SimpleSerializer --version 0.3.0-alpha.16
#r "nuget: Copse.SimpleSerializer, 0.3.0-alpha.16"
#:package Copse.SimpleSerializer@0.3.0-alpha.16
#addin nuget:?package=Copse.SimpleSerializer&version=0.3.0-alpha.16&prerelease
#tool nuget:?package=Copse.SimpleSerializer&version=0.3.0-alpha.16&prerelease
Copse
LINQ for trees. ITreenumerable<T> is to trees what IEnumerable<T> is to sequences — a lazy,
composable abstraction supporting depth-first and breadth-first traversal with 40+ operations:
Where, Select, GetLeaves, PruneBefore, LeaffixAggregate, Union, and more.
No equality contract required: node types need not implement IEquatable<T> or override
GetHashCode.
Install
dotnet add package Copse.Linq --prerelease
Copse.Linq transitively brings in Copse and Copse.Core. Targets net48, net8.0, and netstandard2.0.
Examples
Adapt any tree type by implementing IChildEnumerator<T> — a struct Copse calls to enumerate each
node's children:
using Copse;
using Copse.Linq;
using Copse.Treenumerables;
using System.Linq;
// Node n has children 2n and 2n+1 — a complete binary tree capped at 7.
struct BinaryChildren : IChildEnumerator<int>
{
private int _next;
private readonly int _last;
private bool _disposed;
public BinaryChildren(int parent)
{
_next = parent * 2; // first child of n is 2n...
_last = parent * 2 + 1; // ...and its second (last) child is 2n+1
_disposed = false;
}
public ChildResult<int> MoveNext()
{
if (_disposed || _next > _last || _next > 7)
return default;
var child = new NodeAndSiblingIndex<int>(_next, _next % 2);
_next++;
return new ChildResult<int>(child);
}
public void Dispose() => _disposed = true;
}
ITreenumerable<int> tree = new Treenumerable<int, BinaryChildren>(
ctx => new BinaryChildren(ctx.Node), new[] { 1 });
// 1
// / \
// 2 3
// / \ / \
// 4 5 6 7
Once you have an ITreenumerable<T>, the full operation set is available. Operations compose
without materialization when possible — the streaming operators stay lazy end-to-end — and when
an operation does capture the tree (or might), its return type and docs say so:
int[] preOrder = tree.PreorderTraversal().ToArray(); // [1, 2, 4, 5, 3, 6, 7]
int[] leaves = tree.GetLeaves().ToArray(); // [4, 5, 6, 7]
// Select transforms values while preserving tree structure
int[] doubled = tree
.Select(node => node * 2)
.PreorderTraversal()
.ToArray(); // [2, 4, 8, 10, 6, 12, 14]
// PruneBefore removes a node and its descendants when the predicate is true
int[] topTwo = tree
.PruneBefore((node, position) => position.Depth >= 2)
.GetLeaves()
.ToArray(); // [2, 3]
Where is structural. A filtered-out node's children are promoted to the nearest remaining
ancestor — unlike IEnumerable.Where, which is a flat element filter:
// Remove even nodes. Children of 2 (which are 4 and 5) become children of 1.
// 4 and 6 are also removed but have no children, so they simply vanish.
int[] filtered = tree
.Where(node => node % 2 != 0)
.PreorderTraversal()
.ToArray();
// Result tree: 1(5, 3(7)) => [1, 5, 3, 7]
LeaffixAggregate folds bottom-up, one value per root: every node's accumulation starts
at the node selector (its own contribution), then each child's completed accumulation is
folded in, one child at a time in sibling order:
int subtreeSum = tree
.LeaffixAggregate(
nodeContext => nodeContext.Node,
(accumulate, childAccumulate) => accumulate + childAccumulate)
.First()
.Accumulate; // results are ScanResults: the root's value paired with its fold
// 28 (1 + 2 + 3 + 4 + 5 + 6 + 7)
Packages
| Package | Description |
|---|---|
Copse.Core |
Interfaces, enums, and position types (ITreenumerable<T>, NodePosition, NodeTraversalStrategies, …) |
Copse |
Depth-first and breadth-first traversal engine |
Copse.Linq |
LINQ-style tree operations (Where, Select, GetLeaves, PruneBefore, LeaffixAggregate, Union, …) |
Copse.SimpleSerializer |
Text-format tree serialization for debugging and testing |
Documentation
Full documentation is coming to copselib.org (WIP). For now, the examples above and the source are the reference.
Benchmarks
Performance results are published at copselib.github.io/copse-dotnet.
License
MIT — see LICENSE. © 2023–2026 Jason Boyd.
The disposable utilities in Copse.Disposables (CompositeDisposable, RefCountDisposable,
Disposable.Create, …) are adapted from System.Reactive
(MIT, © .NET Foundation and Contributors) — same names, same semantics, no new concepts.
See THIRD-PARTY-NOTICES.md.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 is compatible. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 is compatible. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETFramework 4.8
- Copse (>= 0.3.0-alpha.16)
- Copse.Async (>= 0.3.0-alpha.16)
- Copse.Core (>= 0.3.0-alpha.16)
- Copse.Core.Async (>= 0.3.0-alpha.16)
- Copse.Primitives (>= 0.3.0-alpha.16)
- System.Memory (>= 4.5.5)
-
.NETStandard 2.0
- Copse (>= 0.3.0-alpha.16)
- Copse.Async (>= 0.3.0-alpha.16)
- Copse.Core (>= 0.3.0-alpha.16)
- Copse.Core.Async (>= 0.3.0-alpha.16)
- Copse.Primitives (>= 0.3.0-alpha.16)
- System.Memory (>= 4.5.5)
-
.NETStandard 2.1
- Copse (>= 0.3.0-alpha.16)
- Copse.Async (>= 0.3.0-alpha.16)
- Copse.Core (>= 0.3.0-alpha.16)
- Copse.Core.Async (>= 0.3.0-alpha.16)
- Copse.Primitives (>= 0.3.0-alpha.16)
-
net8.0
- Copse (>= 0.3.0-alpha.16)
- Copse.Async (>= 0.3.0-alpha.16)
- Copse.Core (>= 0.3.0-alpha.16)
- Copse.Core.Async (>= 0.3.0-alpha.16)
- Copse.Primitives (>= 0.3.0-alpha.16)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.3.0-alpha.19 | 43 | 8/24/2026 |
| 0.3.0-alpha.18 | 56 | 8/17/2026 |
| 0.3.0-alpha.17 | 55 | 8/5/2026 |
| 0.3.0-alpha.16 | 54 | 8/5/2026 |
| 0.3.0-alpha.15 | 51 | 8/5/2026 |
| 0.3.0-alpha.14 | 65 | 8/5/2026 |
| 0.3.0-alpha.13 | 62 | 8/4/2026 |
| 0.3.0-alpha.12 | 60 | 8/4/2026 |
| 0.3.0-alpha.11 | 63 | 8/4/2026 |
| 0.3.0-alpha.10 | 59 | 8/4/2026 |
| 0.3.0-alpha.9 | 61 | 8/2/2026 |
| 0.3.0-alpha.8 | 64 | 8/2/2026 |
| 0.3.0-alpha.7 | 61 | 8/2/2026 |
| 0.3.0-alpha.6 | 64 | 7/17/2026 |
| 0.3.0-alpha.5 | 66 | 7/10/2026 |
| 0.3.0-alpha.4 | 57 | 7/10/2026 |
| 0.3.0-alpha.3 | 69 | 7/10/2026 |
| 0.3.0-alpha.2 | 66 | 7/9/2026 |
| 0.3.0-alpha.1 | 62 | 7/6/2026 |
| 0.2.0-alpha.1 | 58 | 7/6/2026 |