Files
natsnet/docs/plans/phases/phase-3-library-mapping.md
Joseph Doherty 8d68f63e6c chore: update project structure, naming, and add reporting infrastructure
- Update all 7 phase docs with source/target location references
  (golang/ for Go source, dotnet/ for .NET version)
- Rename NATS.Server to ZB.MOM.NatsNet.Server in phase 4-7 docs
- Update solution layout to dotnet/src/ and dotnet/tests/ structure
- Create CLAUDE.md with project summary and phase links
- Update .gitignore: track porting.db, add standard .NET patterns
- Add golang/nats-server as git submodule
- Add reports/generate-report.sh and pre-commit hook
- Add documentation_rules.md to version control
2026-02-26 06:38:56 -05:00

291 lines
12 KiB
Markdown

# Phase 3: Library Mapping
## Objective
Map every external Go dependency detected by the analyzer to its .NET equivalent.
This includes Go standard library packages, well-known third-party libraries, and
NATS ecosystem packages. When Phase 3 is complete, the `library suggest` command
returns an empty list and every import has a documented .NET migration path.
## Prerequisites
- Phases 1 and 2 are complete (database is populated and verified).
- Familiarity with both the Go standard library and .NET BCL / NuGet ecosystem.
- A working `dotnet` CLI for running PortTracker commands.
## Source and Target Locations
| Component | Path |
|---|---|
| Go source code | `golang/` (specifically `golang/nats-server/`) |
| .NET ported version | `dotnet/` |
## Steps
### Step 1: List all unmapped libraries
Start by seeing everything that needs attention:
```bash
dotnet run --project tools/NatsNet.PortTracker -- library suggest --db porting.db
```
This shows all library_mappings entries with status `not_mapped`, sorted by import
path. The output includes the Go import path, the library name, and a usage
description.
If the list is empty, all libraries are already mapped and Phase 3 is complete.
### Step 2: Review the full library list
To see both mapped and unmapped libraries in one view:
```bash
dotnet run --project tools/NatsNet.PortTracker -- library list --db porting.db
```
You can also filter by status:
```bash
dotnet run --project tools/NatsNet.PortTracker -- library list --status not_mapped --db porting.db
dotnet run --project tools/NatsNet.PortTracker -- library list --status mapped --db porting.db
```
### Step 3: Map each library
For each unmapped library, determine the appropriate .NET equivalent using the
reference table below, then record the mapping:
```bash
dotnet run --project tools/NatsNet.PortTracker -- library map <id> \
--package "<NuGet package or BCL>" \
--namespace "<.NET namespace>" \
--notes "<migration notes>" \
--db porting.db
```
**Example -- mapping `encoding/json`:**
```bash
dotnet run --project tools/NatsNet.PortTracker -- library map 1 \
--package "System.Text.Json" \
--namespace "System.Text.Json" \
--notes "Use JsonSerializer. Consider source generators for AOT." \
--db porting.db
```
**Example -- mapping `github.com/klauspost/compress`:**
```bash
dotnet run --project tools/NatsNet.PortTracker -- library map 12 \
--package "System.IO.Compression" \
--namespace "System.IO.Compression" \
--notes "S2/Snappy codec needs evaluation; may need custom impl or IronSnappy NuGet." \
--db porting.db
```
Repeat for every entry in the `library suggest` output.
### Step 4: Handle libraries that need custom implementations
Some Go libraries have no direct .NET equivalent and will require custom code.
For these, record the mapping with a descriptive note:
```bash
dotnet run --project tools/NatsNet.PortTracker -- library map <id> \
--package "Custom" \
--namespace "NatsNet.Internal" \
--notes "No direct equivalent; requires custom implementation. See <details>." \
--db porting.db
```
### Step 5: Verify all libraries are mapped
Run the suggest command again -- it should return an empty list:
```bash
dotnet run --project tools/NatsNet.PortTracker -- library suggest --db porting.db
```
Expected output:
```
All libraries have been mapped!
```
Also verify via the full list:
```bash
dotnet run --project tools/NatsNet.PortTracker -- library list --db porting.db
```
Every entry should show status `mapped` (or `verified` if you have already
validated the mapping in code).
### Step 6: Run the phase check
Confirm Phase 1 now shows full completion including library mappings:
```bash
dotnet run --project tools/NatsNet.PortTracker -- phase check 1 --db porting.db
```
Expected:
```
Phase 1 Checklist:
[x] Modules populated: <N>
[x] Features populated: <N>
[x] Unit tests populated: <N>
[x] Dependencies mapped: <N>
[x] Libraries identified: <N>
[x] All libraries mapped: <N>/<N>
```
### Step 7: Export the mapping report
Save the complete library mapping state for reference during porting:
```bash
dotnet run --project tools/NatsNet.PortTracker -- report export \
--format md \
--output docs/reports/phase-3-library-mapping.md \
--db porting.db
```
## Common Go to .NET Mappings Reference
Use this table as a starting point when determining .NET equivalents. Adapt based
on the specific usage patterns found in the NATS server source.
### Go Standard Library
| Go Package | .NET Equivalent | Notes |
|---|---|---|
| `encoding/json` | `System.Text.Json` | Use `JsonSerializer`; consider source generators for performance |
| `encoding/binary` | `System.Buffers.Binary.BinaryPrimitives` | For endian-aware reads/writes |
| `encoding/base64` | `System.Convert` | `Convert.ToBase64String` / `Convert.FromBase64String` |
| `encoding/hex` | `System.Convert` | `Convert.ToHexString` (.NET 5+) |
| `encoding/pem` | `System.Security.Cryptography.PemEncoding` | .NET 5+ |
| `sync` | `System.Threading` | `Mutex` -> `lock` / `Monitor`; `RWMutex` -> `ReaderWriterLockSlim`; `WaitGroup` -> `CountdownEvent`; `Once` -> `Lazy<T>` |
| `sync/atomic` | `System.Threading.Interlocked` | `Interlocked.Increment`, `CompareExchange`, etc. |
| `net` | `System.Net.Sockets` | `TcpListener`, `TcpClient`, `Socket` |
| `net/http` | `System.Net.Http` / `Microsoft.AspNetCore` | Client: `HttpClient`; Server: Kestrel / minimal APIs |
| `net/url` | `System.Uri` | `Uri`, `UriBuilder` |
| `crypto/tls` | `System.Net.Security.SslStream` | Wrap `NetworkStream` with `SslStream` |
| `crypto/x509` | `System.Security.Cryptography.X509Certificates` | `X509Certificate2` |
| `crypto/sha256` | `System.Security.Cryptography.SHA256` | `SHA256.HashData()` (.NET 8+) |
| `crypto/ed25519` | `System.Security.Cryptography` | `Ed25519` support in .NET 9+ |
| `crypto/rand` | `System.Security.Cryptography.RandomNumberGenerator` | `RandomNumberGenerator.Fill()` |
| `time` | `System.TimeSpan` / `System.Threading.Timer` | `time.Duration` -> `TimeSpan`; `time.Ticker` -> `PeriodicTimer`; `time.After` -> `Task.Delay` |
| `time` (parsing) | `System.DateTime` / `System.DateTimeOffset` | `DateTime.Parse`, custom formats |
| `fmt` | String interpolation / `String.Format` | `$"..."` for most cases; `String.Format` for dynamic |
| `io` | `System.IO` | `Reader` -> `Stream`; `Writer` -> `Stream`; `io.Copy` -> `Stream.CopyTo` |
| `io/fs` | `System.IO` | `Directory`, `File`, `FileInfo` |
| `bufio` | `System.IO.BufferedStream` | Or `StreamReader` / `StreamWriter` |
| `bytes` | `System.Buffers` / `MemoryStream` | `bytes.Buffer` -> `MemoryStream` or `ArrayBufferWriter<byte>` |
| `strings` | `System.String` / `System.Text.StringBuilder` | Most methods have direct equivalents |
| `strconv` | `int.Parse`, `double.Parse`, etc. | Or `Convert` class |
| `context` | `CancellationToken` | `context.Context` -> `CancellationToken`; `context.WithCancel` -> `CancellationTokenSource` |
| `os` | `System.Environment` / `System.IO` | `os.Exit` -> `Environment.Exit`; file ops -> `File` class |
| `os/signal` | `System.Runtime.Loader.AssemblyLoadContext` | `UnloadingEvent` or `Console.CancelKeyPress` |
| `path/filepath` | `System.IO.Path` | `Path.Combine`, `Path.GetDirectoryName`, etc. |
| `sort` | `System.Linq` / `Array.Sort` | LINQ `.OrderBy()` or in-place `Array.Sort` |
| `math` | `System.Math` | Direct equivalent |
| `math/rand` | `System.Random` | `Random.Shared` for thread-safe usage (.NET 6+) |
| `regexp` | `System.Text.RegularExpressions.Regex` | Consider source generators for compiled patterns |
| `errors` | `System.Exception` | Go errors -> .NET exceptions; `errors.Is` -> pattern matching |
| `log` | `Serilog` | Project choice: Serilog via `Microsoft.Extensions.Logging` |
| `testing` | `xUnit` | `testing.T` -> xUnit `[Fact]`/`[Theory]`; `testing.B` -> BenchmarkDotNet |
| `flag` | `System.CommandLine` | Or `Microsoft.Extensions.Configuration` |
| `embed` | Embedded resources | `.csproj` `<EmbeddedResource>` items |
| `runtime` | `System.Runtime` / `System.Environment` | `runtime.GOOS` -> `RuntimeInformation.IsOSPlatform` |
### NATS Ecosystem Libraries
| Go Package | .NET Equivalent | Notes |
|---|---|---|
| `github.com/nats-io/jwt/v2` | Custom / evaluate existing | JWT claims for NATS auth; may need custom implementation matching NATS JWT spec |
| `github.com/nats-io/nkeys` | Custom implementation | Ed25519 key pairs for NATS authentication; use `System.Security.Cryptography` Ed25519 |
| `github.com/nats-io/nuid` | Custom / `System.Guid` | NATS unique IDs; simple custom implementation or adapt to `Guid` if format is flexible |
| `github.com/nats-io/nats.go` | `NATS.Net` (official) | Only used in tests; the official .NET NATS client |
### Third-Party Libraries
| Go Package | .NET Equivalent | Notes |
|---|---|---|
| `github.com/klauspost/compress` | `System.IO.Compression` | General compression: `GZipStream`, `DeflateStream`. S2/Snappy: evaluate IronSnappy NuGet or custom port |
| `github.com/minio/highwayhash` | Custom / NuGet | HighwayHash implementation; search NuGet or port the algorithm |
| `golang.org/x/crypto` | `System.Security.Cryptography` | `bcrypt` -> `Rfc2898DeriveBytes` or BCrypt.Net NuGet; `argon2` -> Konscious.Security NuGet |
| `golang.org/x/sys` | `System.Runtime.InteropServices` | Platform-specific syscalls -> P/Invoke or `RuntimeInformation` |
| `golang.org/x/time` | `System.Threading.RateLimiting` | `rate.Limiter` -> `RateLimiter` (.NET 7+); `TokenBucketRateLimiter` or `SlidingWindowRateLimiter` |
| `golang.org/x/text` | `System.Globalization` | Unicode normalization, encoding detection |
## Mapping Decision Guidelines
When choosing a .NET equivalent, follow these priorities:
1. **BCL first**: Prefer built-in .NET Base Class Library types over NuGet packages.
2. **Official packages second**: If BCL does not cover it, prefer
`Microsoft.*` or `System.*` NuGet packages.
3. **Well-maintained NuGet third**: Choose packages with active maintenance,
high download counts, and compatible licenses.
4. **Custom implementation last**: Only write custom code when no suitable
package exists. Document the rationale in the mapping notes.
For each mapping, consider:
- **API surface**: Does the .NET equivalent cover all methods used in the Go code?
- **Performance**: Are there performance-critical paths that need benchmarking?
- **Thread safety**: Go's concurrency model differs from .NET. Note any
synchronization concerns.
- **Platform support**: Does the .NET package work on all target platforms
(Linux, macOS, Windows)?
## Completion Criteria
Phase 3 is complete when ALL of the following are true:
- [ ] `library suggest` returns "All libraries have been mapped!"
- [ ] Every entry in `library list` shows status `mapped` or `verified`.
- [ ] Each mapping includes a `--package` (the NuGet package or BCL assembly),
a `--namespace` (the .NET namespace to use), and `--notes` (migration
guidance).
- [ ] `phase check 1` shows all items checked including "All libraries mapped".
- [ ] A mapping report has been exported for reference.
## Troubleshooting
### "Library <id> not found"
The ID you passed to `library map` does not exist. Run `library suggest` to get
the current list of IDs and their import paths.
### Unsure which .NET package to use
For unfamiliar Go packages:
1. Check what the package does in the Go source (look at the import usage in the
files listed by the analyzer).
2. Search NuGet.org for equivalent functionality.
3. Check if the Go package is a thin wrapper around a well-known algorithm that
.NET implements natively.
4. When in doubt, map it as "Custom" with detailed notes and revisit during
the porting phase.
### Multiple .NET options for one Go package
When there are several valid .NET equivalents (e.g., `Newtonsoft.Json` vs
`System.Text.Json`), prefer the one that:
- Is part of the BCL or a Microsoft package.
- Has better performance characteristics.
- Has source generator support for AOT compilation.
Record the alternatives in the `--notes` field so the decision can be revisited.
### Stdlib packages showing as unmapped
The analyzer classifies imports as stdlib vs external based on whether the first
path component contains a dot. Standard library packages like `encoding/json`,
`net/http`, etc. should still be recorded in the library_mappings table so that
every import path has a documented .NET migration path. Map them using the
reference table above.