Skip to content

Commit c915b3d

Browse files
authored
IPv6 and dual stack implementation (#37)
* data source links applied, type renaming * phone parser * unmarshalling empty value fix * empty value unmarshalling fix * ipv6 implementation * ip dual stack implementation --------- Co-authored-by: ivan-lemiashonak <[email protected]>
1 parent 5a238dd commit c915b3d

File tree

8 files changed

+745
-64
lines changed

8 files changed

+745
-64
lines changed

ip/ip.go

Lines changed: 63 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,19 @@ package ip
33
import (
44
"database/sql/driver"
55
"encoding/json"
6+
"errors"
67
"fmt"
7-
"net/netip"
88
)
99

10-
type IPv4 string
10+
type IP struct {
11+
v4 IPv4
12+
v6 IPv6
13+
raw string
14+
isV6 bool
15+
}
1116

1217
// Value implementation of driver.Valuer
13-
func (ip IPv4) Value() (value driver.Value, err error) {
18+
func (ip IP) Value() (value driver.Value, err error) {
1419
if err = ip.Validate(); err != nil {
1520
return nil, err
1621
}
@@ -19,24 +24,34 @@ func (ip IPv4) Value() (value driver.Value, err error) {
1924
}
2025

2126
// Validate implementation of ozzo-validation Validate interface
22-
func (ip IPv4) Validate() error {
23-
_, err := FromString(ip.String())
27+
func (ip IP) Validate() error {
28+
var fromStringIP, err = FromString(ip.String())
2429
if err != nil {
25-
return fmt.Errorf("'%s' is not an valid IPv4 address, err: %w", ip, err)
30+
return fmt.Errorf("'%s' is not an valid IP address, err: %w", ip, err)
2631
}
2732

28-
return nil
33+
if fromStringIP.raw == ip.raw &&
34+
fromStringIP.isV6 == ip.isV6 &&
35+
fromStringIP.v4 == ip.v4 &&
36+
fromStringIP.v6 == ip.v6 {
37+
return nil
38+
}
39+
40+
return errors.New(`IP inconsistency error`)
2941
}
3042

3143
// UnmarshalJSON unmarshall implementation for IP
32-
func (ip *IPv4) UnmarshalJSON(data []byte) error {
33-
var str string
34-
if err := json.Unmarshal(data, &str); err != nil {
44+
func (ip *IP) UnmarshalJSON(data []byte) error {
45+
var (
46+
str string
47+
err error
48+
)
49+
if err = json.Unmarshal(data, &str); err != nil {
3550
return err
3651
}
3752

38-
value := IPv4(str)
39-
if err := value.Validate(); err != nil {
53+
var value IP
54+
if value, err = FromString(str); err != nil && value.Validate() != nil {
4055
return err
4156
}
4257

@@ -45,24 +60,50 @@ func (ip *IPv4) UnmarshalJSON(data []byte) error {
4560
return nil
4661
}
4762

63+
// MarshalJSON marshall implementation for IP
64+
func (ip IP) MarshalJSON() ([]byte, error) {
65+
return json.Marshal(ip.raw)
66+
}
67+
4868
// String implementation of Stringer interface
49-
func (ip IPv4) String() string {
50-
return string(ip)
69+
func (ip IP) String() string {
70+
return ip.raw
5171
}
5272

53-
func FromString(value string) (IPv4, error) {
73+
func (ip IP) IPv4() IPv4 {
74+
return ip.v4
75+
}
76+
77+
func (ip IP) IPv6() IPv6 {
78+
return ip.v6
79+
}
80+
81+
func (ip IP) IsIPv6() bool {
82+
return ip.isV6
83+
}
84+
85+
func FromString(value string) (IP, error) {
5486
if value == "" {
55-
return "", fmt.Errorf("empty value")
87+
return IP{}, fmt.Errorf("empty value")
5688
}
5789

58-
var addr, err = netip.ParseAddr(value)
59-
if err != nil {
60-
return "", err
90+
var v4Addr, err = V4FromString(value)
91+
if err == nil {
92+
return IP{
93+
v4: v4Addr,
94+
isV6: false,
95+
raw: value,
96+
}, nil
6197
}
6298

63-
if !addr.Is4() {
64-
return "", fmt.Errorf("not an IPv4 address")
99+
var v6Addr IPv6
100+
if v6Addr, err = V6FromString(value); err == nil {
101+
return IP{
102+
v6: v6Addr,
103+
isV6: true,
104+
raw: value,
105+
}, nil
65106
}
66107

67-
return IPv4(addr.String()), nil
108+
return IP{}, errors.New("value isn't fit neither v4 nor v6 IP")
68109
}

0 commit comments

Comments
 (0)