Skip to content

Refresh: modernize targets/deps, fix correctness bugs, deprecate misleading APIs#4

Merged
PFalkowski merged 6 commits into
masterfrom
refresh/modernize-2026
Jun 13, 2026
Merged

Refresh: modernize targets/deps, fix correctness bugs, deprecate misleading APIs#4
PFalkowski merged 6 commits into
masterfrom
refresh/modernize-2026

Conversation

@PFalkowski

Copy link
Copy Markdown
Owner

Refreshes this long-dormant package: fixes real correctness bugs, modernizes the build, and deprecates two misleadingly-named APIs without breaking existing consumers.

Correctness fixes (non-breaking)

  • IsEquivalent — was returning only the last element's membership and de-duplicating one side via HashSet. Now does proper multiset (bag) equality. (Genuinely returned wrong answers, e.g. {"3","1","2"} vs {"4","1","2"}true.)
  • AsMemory / AsMemoryDecimal — wrong divisor/suffix at the exbibyte+ and zettabyte+ tiers. Rewritten to drive off the existing BinaryOrders/DecimalOrders tables (also removes the duplicated if/else ladders).
  • Scale<T> over non-double IConvertibleCast<double>() threw InvalidCastException on boxed ints; now uses Convert.ToDouble.
  • Scale(IEnumerable<double>) — computed min/max off the original source instead of the materialized copy (double-enumerated lazy sequences).
  • AsColor — encoder packed bytes inconsistently with the decoder; now produces a standard ARGB int that round-trips.

Modernization

  • Multi-target netstandard2.0;net8.0 (was EOL net6.0 only). LangVersion latest, ships XML docs. Removed the bogus NETSTANDARD2_0 DefineConstants and deprecated empty PackageLicenseUrl.
  • netstandard2.0 compatibility: cross-target shared Random (Random.Shared is net6+), replaced StringBuilder.AppendJoin and Enumerable.ToHashSet.
  • Bumped test deps (Test.Sdk 17.12, xunit 2.9.2, NSubstitute 5.3), test project to net8.0, removed legacy <Service> entry.

Deprecations (the only breaking-ish part — handled via [Obsolete] shims)

  • InClosedRange/InOpenRange had inverted semantics → added InRangeInclusive / InRangeExclusive; old names kept as [Obsolete] with unchanged behavior.
  • ConstructLine's angleDegrees was actually radians → added ConstructLineFromRadians (identical) and ConstructLineFromDegrees; old method [Obsolete].
  • Version bumped to 10.0.0.

Tests

178/178 passing, clean build (0 warnings) on both TFMs. Added regression coverage for every fixed bug and the new methods; existing range tests retained as shim coverage.

🤖 Generated with Claude Code

PFalkowski and others added 6 commits February 16, 2025 18:46
…ndard

# Conflicts:
#	Extensions.Standard/Extensions.Standard.csproj
Correctness fixes (non-breaking):
- IsEquivalent: was returning only the last element's membership and
  de-duplicating via HashSet; now does proper multiset (bag) equality.
- AsMemory/AsMemoryDecimal: wrong divisor/suffix at the exbibyte+ and
  zettabyte+ tiers; rewritten to drive off the existing BinaryOrders/
  DecimalOrders tables (also removes the duplicated if/else ladders).
- Scale<T> over non-double IConvertible: Cast<double>() threw
  InvalidCastException on boxed ints; now uses Convert.ToDouble.
- Scale(IEnumerable<double>): computed min/max off the original source
  instead of the materialized copy (double enumeration of lazy seqs).
- AsColor encoder packed bytes in an order inconsistent with the
  decoder; now produces a standard ARGB int that round-trips.

Modernization:
- Multi-target netstandard2.0;net8.0 (was EOL net6.0 only); set
  LangVersion latest; ship XML docs. Removed bogus NETSTANDARD2_0
  DefineConstants and deprecated empty PackageLicenseUrl.
- netstandard2.0 compatibility: cross-target shared Random (Random.Shared
  is net6+), replaced StringBuilder.AppendJoin and Enumerable.ToHashSet.
- Bumped test deps (Test.Sdk 17.12, xunit 2.9.2, NSubstitute 5.3),
  test project to net8.0, removed legacy <Service> entry.
- Version 9.2.0, copyright 2026.

Tests: added regression coverage for IsEquivalent multiplicity, AsMemory
high orders, generic Scale, and AsColor round-trip; cleaned analyzer
warnings. 174/174 passing, clean build on both TFMs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The names InClosedRange/InOpenRange had inverted semantics (closed
excluded endpoints, open included them) and ConstructLine's
"angleDegrees" parameter was actually interpreted as radians. Rather
than silently change behavior, add correctly-named members and keep the
old names as [Obsolete] shims with unchanged behavior:

- InRangeInclusive ([from,to], endpoints included)
- InRangeExclusive ((from,to), endpoints excluded)
- ConstructLineFromRadians (identical to the old ConstructLine)
- ConstructLineFromDegrees (converts degrees, what the old name implied)

Internal Scale call moved to InRangeExclusive. Existing range tests
retained (pragma-wrapped) as shim coverage; added tests for the new
methods plus a shim-equivalence check. Bumped to 10.0.0; README updated.
178/178 passing, clean build on both TFMs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- ci.yml: restore, build (Release, both TFMs) and test on every push to
  master, every PR, and manual dispatch.
- publish.yml: on a v*.*.* tag (or manual dispatch with an explicit
  version), restore/build/test, then pack with the tag-derived version
  and push to NuGet (--skip-duplicate). Requires a NUGET_API_KEY secret.
- Bundle README.md into the package and add a CI status badge.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
checkout@v4/setup-dotnet@v4 run on the soon-deprecated Node 20. Pin to
checkout@v6 and setup-dotnet@v5.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@PFalkowski PFalkowski merged commit a96a19b into master Jun 13, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant