|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Repository overview |
| 6 | + |
| 7 | +This is the **nanoFramework.System.Collections** library — a re-implementation of the `System.Collections` / `System.Collections.Generic` collection types for [.NET **nanoFramework**](https://nanoframework.net/), a stripped-down .NET runtime that runs directly on embedded microcontrollers (ESP32, STM32, etc.). It is NOT a normal .NET/.NET Standard project: it targets a custom, constrained CLR (`nanoCLR`) with its own project system, MSBuild tooling, and a `mscorlib` that only implements a subset of the BCL. |
| 8 | + |
| 9 | +Key implication for any change: don't assume APIs from desktop `System.Collections` are available (LINQ, `Span<T>`, `IEqualityComparer<T>` generics customization, reflection-heavy patterns, etc. may not exist in nanoFramework's `mscorlib`). Always check `nanoFramework.System.Collections/Collections/**` for existing patterns before introducing a new API surface. |
| 10 | + |
| 11 | +## Solution layout |
| 12 | + |
| 13 | +- `nanoFramework.System.Collections.sln` — main solution. |
| 14 | +- `nanoFramework.System.Collections/` — the library project (`nanoFramework.System.Collections.nfproj`, `RootNamespace=System.Collections`, `NF_IsCoreLibrary=True`). |
| 15 | + - `Collections/` — non-generic types: `Hashtable` (+ `Hashtable.Bucket.cs`), `Queue`, `Stack`, `IDictionary`, `IDictionaryEnumerator`, `DictionaryEntry`. |
| 16 | + - `Collections/Generic/` — generic types: `Dictionary<TKey,TValue>`, `List<T>`, `KeyValuePair<TKey,TValue>`, `IDictionary<TKey,TValue>`, `IList<T>`, `IReadOnlyCollection<T>`, `IReadOnlyDictionary<TKey,TValue>`, `IReadOnlyList<T>`, debugger-view helpers. |
| 17 | +- `Tests/` — one `.nfproj` test project per area, each producing an `NFUnitTest` assembly and referencing the library via `ProjectReference`: |
| 18 | + - `HashtableTests/`, `QueueTests/`, `StackTests/`, `GenericCollections/` (covers `Dictionary<TKey,TValue>` and `List<T>`). |
| 19 | + - Tests use `nanoFramework.TestFramework` (`[TestClass]`, `[TestMethod]`, `[Setup]`, `Assert.*` — MSTest-like API, not xUnit/NUnit). |
| 20 | +- `packages/` — restored NuGet packages, including the pinned nanoCLR/test-runner tooling (checked into `packages.lock.json` per project). |
| 21 | +- `version.json` — Nerdbank.GitVersioning config; version is derived from git height, do not hand-edit assembly versions. |
| 22 | +- `azure-pipelines.yml` — CI entry point (Azure DevOps, using shared templates from `nanoframework/nf-tools`). Runs build, unit tests (via `.runsettings`), SonarCloud analysis, and NuGet publish. |
| 23 | +- `.github/workflows/pr-checks.yml` — GitHub Actions PR checks: verifies `packages.lock.json` is current and that referenced nanoFramework NuGet packages are up to date. |
| 24 | + |
| 25 | +## Prerequisites for local development |
| 26 | + |
| 27 | +Building/testing requires Visual Studio 2022 with the **nanoFramework VS2022 extension** installed (provides the `nanoFramework` MSBuild project system imported by every `.nfproj`, i.e. `$(MSBuildExtensionsPath)\nanoFramework\v1.0\NFProjectSystem.*`). Without the extension, `.nfproj` files will not build from the command line via plain `dotnet build`/`msbuild`. |
| 28 | + |
| 29 | +Building/running tests also requires the **nanoFramework Test Explorer / nanoclr runner** components (installed alongside the VS extension, or via `nanoclr` global tool) since tests execute against the nanoCLR interpreter, not the desktop CLR. |
| 30 | + |
| 31 | +## Common commands |
| 32 | + |
| 33 | +```bash |
| 34 | +# Restore packages for the whole solution (locked mode, matches CI) |
| 35 | +nuget restore nanoFramework.System.Collections.sln |
| 36 | + |
| 37 | +# Build the full solution in Visual Studio / via msbuild (requires nanoFramework VS extension) |
| 38 | +msbuild nanoFramework.System.Collections.sln /p:Configuration=Release /p:Platform="Any CPU" |
| 39 | +``` |
| 40 | + |
| 41 | +Running tests locally is normally done through Visual Studio's Test Explorer (the nanoFramework Test Adapter executes each `.nfproj` test assembly against a virtual nanoCLR instance). Solution-wide settings for the test run live in [.runsettings](.runsettings); each test project also has its own `nano.runsettings`. There is no plain `dotnet test` path — the adapter is VS/nanoclr-specific. |
| 42 | + |
| 43 | +To run a **single test**, use Visual Studio Test Explorer and run/debug the individual `[TestMethod]`. There is no supported CLI equivalent in this repo. |
| 44 | + |
| 45 | +## Architecture notes |
| 46 | + |
| 47 | +- **`Hashtable`** (`Collections/Hashtable.cs` + `Hashtable.Bucket.cs`) is a from-scratch, non-generic hashtable. Unlike desktop .NET's `Hashtable`, **it does not support hash collisions** — every key must produce a truly unique `GetHashCode()` within the table (see the type's XML doc remarks). Backed by a private `Bucket[]` array (`internal class Bucket { object _key; object _value; uint _hash; }`), sized via `InitialSize`/load factor, with a static `_syncLock` for thread safety and a `_version` field for enumerator invalidation (fail-fast on concurrent modification). |
| 48 | +- **`Dictionary<TKey, TValue>`** (`Collections/Generic/Dictionary.cs`) mirrors the modern desktop BCL implementation's bucket/entries-with-free-list design (`_buckets`, `_entries`, `StartOfFreeList` encoding for the free chain, `_freeList`/`_freeCount`), including `KeyCollection`/`ValueCollection` nested views. Keys are constrained `where TKey : notnull`. This is a different, newer implementation strategy than `Hashtable` — don't assume the two share internals. |
| 49 | +- **`List<T>`**, `Queue`, `Stack` follow standard growable-array patterns. |
| 50 | +- Non-generic and generic collection interfaces are hand-rolled locally (`Collections/IDictionary.cs`, `Collections/Generic/IList.cs`, etc.) rather than coming from a full BCL — check whether an interface member you expect actually exists here before using it. |
| 51 | +- The `.nfproj` excludes certain classes from stub/skeleton generation for the native interop layer (`NFMDP_PE_ExcludeClassByName` in the `.nfproj`: `ThisAssembly`, `DictionaryEntry`, `IDictionaryEnumerator`) — these are pure-managed types with no native counterpart. |
| 52 | +- Assembly is strong-named (`key.snk`, `SignAssembly=true`) and versioned via Nerdbank.GitVersioning (`version.json`) — don't hand-edit version/assembly-info files. |
| 53 | + |
| 54 | +## CI/PR expectations |
| 55 | + |
| 56 | +- `packages.lock.json` files (one per `.nfproj`) must stay in sync with `packages.config`; PR checks fail if they drift. Restore with locked mode (`RestoreLockedMode=true` is forced when `TF_BUILD`/`ContinuousIntegrationBuild` is set) rather than hand-editing lock files. |
| 57 | +- CI also checks that referenced nanoFramework NuGet packages (`nanoFramework.CoreLibrary`, `nanoFramework.TestFramework`, etc.) are current — expect automated dependency-update PRs/commits (see recent git history) targeting `.nfproj`/`packages.config`/`packages.lock.json`. |
0 commit comments