# 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/` |

## Milestone Tracking

This phase corresponds to **Milestone 3** in [Gitea](https://gitea.dohertylan.com/dohertj2/natsnet/milestone/3). When starting this phase, verify the milestone is open. Assign relevant issues to this milestone as work progresses.

### Issue Updates

Each completion criterion has a corresponding Gitea issue. Update issues as you work:

- **Starting a criterion**: Add a comment noting work has begun
- **Blocked**: Add a comment describing the blocker
- **Complete**: Close the issue with a comment summarizing the result (e.g., counts, verification output)

Close issues via CLI:
```bash
curl -s -X PATCH "https://gitea.dohertylan.com/api/v1/repos/dohertj2/natsnet/issues/{N}" \
  -H "Content-Type: application/json" \
  -H "Authorization: token $GITEA_TOKEN" \
  -d '{"state":"closed"}'
```
Or close via the Gitea web UI.

## 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:

- [ ] [#30](https://gitea.dohertylan.com/dohertj2/natsnet/issues/30) `library suggest` returns "All libraries have been mapped!"
- [ ] [#21](https://gitea.dohertylan.com/dohertj2/natsnet/issues/21) Every entry in `library list` shows status `mapped` or `verified`.
- [ ] [#22](https://gitea.dohertylan.com/dohertj2/natsnet/issues/22) Each mapping includes a `--package` (the NuGet package or BCL assembly),
      a `--namespace` (the .NET namespace to use), and `--notes` (migration
      guidance).
- [ ] [#23](https://gitea.dohertylan.com/dohertj2/natsnet/issues/23) `phase check 1` shows all items checked including "All libraries mapped".
- [ ] [#24](https://gitea.dohertylan.com/dohertj2/natsnet/issues/24) A mapping report has been exported for reference.
- [ ] Close the Phase 3 milestone in Gitea:
  ```bash
  curl -s -X PATCH "https://gitea.dohertylan.com/api/v1/repos/dohertj2/natsnet/milestones/3" \
    -H "Content-Type: application/json" \
    -H "Authorization: token $GITEA_TOKEN" \
    -d '{"state":"closed"}'
  ```
  Or close it via the Gitea web UI at https://gitea.dohertylan.com/dohertj2/natsnet/milestone/3

## 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.
