ipflag 0.1.0

Human-friendly IP -> country flag display core (resolver-pluggable, no data bundled).
Documentation
# IP Flag (ipflag)

IP Flag is a tiny, resolver-pluggable Rust crate that turns IP addresses into a human-friendly country display (flag + country code). It is designed for communities, forums, comment sections, moderation logs, analytics dashboards, and anywhere an IP string is hard to read at a glance.

The core idea is simple:

- IP Flag does display.
- IP Flag does not ship geolocation data.
- IP Flag does not call external APIs.
- IP Flag does not require updates.

If you want real “IP → country” resolution, you provide it via a resolver implementation (or via a separate extension crate). This keeps the core maintenance-free and makes the ecosystem extensible.

---

## Why IP Flag exists

Raw IP addresses are noisy and not human-friendly.

In real community moderation, the question is often not “what is the exact IP?”, but “what pattern do we see across many comments?” A country flag or country code makes it easy to scan a thread and quickly notice clusters and anomalies.

IP Flag does not make claims about intent or manipulation. It only helps humans see patterns more clearly.

---

## What IP Flag does (and does not)

### IP Flag does

- Parse IPv4/IPv6
- Classify IP scope:
  - `Private` (LAN / internal)
  - `Special` (loopback, multicast, documentation ranges, etc.)
  - `Public` (eligible for resolution)
- if `Public`, call your resolver and display:
  - Flag emoji (🇰🇷, 🇺🇸, 🇷🇺, ...)
  - Country code (KR, US, RU, ...)
- Provide formatting helpers for common UI output styles

### IP Flag does not

- Bundle MaxMind or any GeoIP database
- Contact third-party APIs
- Track, store, or log anything
- Decide what is “suspicious”
- Maintain an ever-changing list of countries or names

---

## Installation

Add the crate to your `Cargo.toml`:

```toml
ipflag = "0.1.0"
```

Then import what you need:

- `tag_ip` / `tag_addr` to generate tags
- `IpResolver` to plug in your own resolution logic
- `NoopResolver` for “display-only” usage without resolution

---

## Core usage

### Use IP Flag by itself (no resolver data)

This mode is still useful because it cleanly categorizes internal/special addresses and gives you a consistent display output. 

Example:

```rust
use ipflag::{tag_ip, NoopResolver};

fn main() {
    let t1 = tag_ip(&NoopResolver, "192.168.0.10").unwrap();
    println!("{}", t1); // 🏠 PRIVATE

    let t2 = tag_ip(&NoopResolver, "127.0.0.1").unwrap();
    println!("{}", t2); // ⚙️ SPECIAL

    let t3 = tag_ip(&NoopResolver, "8.8.8.8").unwrap();
    println!("{}", t3); // 🌐 UNKNOWN
}
```

What you get here is:

- A reliable “this is internal” / “this is special” / “this is public but unknown” signal
- A stable output format suitable for UI and logs
- Zero dependencies and zero update requirements

### 2) Provide a resolver (real country flags)

To show real countries, you implement one trait: `IpResolver`.

This resolver can be anything:

- a MaxMind reader
- an IP-to-country map from your own data source
- a corporate CDN header mapping
- a custom enterprise threat intel source
- a quick prototype rule-based resolver

Example resolver (hard-coded for demonstration):

```rust
use ipflag::{CountryCode, IpResolver, tag_ip};
use std::net::IpAddr;

struct DemoResolver;

impl IpResolver for DemoResolver {
    type Error = core::convert::Infallible;

    fn resolve(&self, _ip: IpAddr) -> Result<Option<CountryCode>, Self::Error> {
        Ok(CountryCode::new("KR"))
    }
}

fn main() {
    let tag = tag_ip(&DemoResolver, "8.8.8.8").unwrap();
    println!("{}", tag); // 🇰🇷 KR
}
```

---

## How resolution works

IP Flag calls your resolver only for Public IPs.

- Private IPs never call the resolver → always `🏠 PRIVATE`
- Special IPs never call the resolver → always `⚙️ SPECIAL`
- Public IPs call the resolver:
  - resolver returns `Some(CountryCode)``IpTag::Country(code)` → displays `🇰🇷 KR`
  - resolver returns None → `IpTag::Unknown` → displays `🌐 UNKNOWN`

This is important for correctness, performance, and privacy. It prevents “fake resolution” for private and special ranges and keeps your resolver focused on real public IPs only.

---

## Output formats (UI-friendly)

IpTag `implements` Display, so you can directly print it:

```Rust
println!("{}", tag); // default output
```

If you want different display styles, use `TagFormat`:

```rust
use ipflag::{TagFormat};

println!("{}", tag.format(TagFormat::FlagAndCode)); // "🇰🇷 KR"
println!("{}", tag.format(TagFormat::FlagOnly));    // "🇰🇷"
println!("{}", tag.format(TagFormat::CodeOnly));    // "KR"
```

For non-country tags, the default output is:

- `🏠 PRIVATE`
- `⚙️ SPECIAL`
- `🌐 UNKNOWN`

This is intentional: it keeps log output consistent and predictable.

---

## Minimal “community comment display” example

A typical usage is to append the tag next to a comment’s “anonymous” label:

```rust
use ipflag::{tag_ip, NoopResolver, TagFormat};

fn display_anonymous(ip: &str) -> String {
    let tag = tag_ip(&NoopResolver, ip).unwrap();
    format!("Anonymous {}", tag.format(TagFormat::FlagOnly))
}

fn main() {
    println!("{}", display_anonymous("192.168.1.10")); // Anonymous 🏠
    println!("{}", display_anonymous("8.8.8.8"));      // Anonymous 🌐
}
```

In production, replace `NoopResolver` with your real resolver implementation.

---

## Privacy and security notes

- IP Flag does not perform network requests.
- IP Flag does not store IPs.
- IP Flag does not log anything.
- Your resolver may, depending on your implementation.

In community settings, you should consider privacy laws and policies. A common approach is masking IPs in UI and logs while still using flags/codes for pattern visibility.

---

## Non-goals

- “Detect manipulation” or “label someone as suspicious”
- Provide absolute truth about user identity or nationality
- Replace moderation judgment
- Provide a global geolocation database

IP Flag is a display utility. The interpretation is yours.

---

## Contributing

Contributions that keep the core minimal and stable are welcome:

- Bug fixes
- Better IPv4/IPv6 scope classification edge cases
- Output formatting improvements
- More examples and documentation

Anything that adds bundled data sources or external network calls should live in extension crates, not in the core.

---

## License

[Apache-2.0](LICENSE)