forked from paulmach/osm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
object.go
147 lines (124 loc) · 3.42 KB
/
object.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package osm
import (
"fmt"
"strconv"
"strings"
)
// ObjectID encodes the type and ref of an osm object,
// e.g. nodes, ways, relations, changesets, notes and users.
type ObjectID int64
// Type returns the Type of the object.
func (id ObjectID) Type() Type {
switch id & typeMask {
case nodeMask:
return TypeNode
case wayMask:
return TypeWay
case relationMask:
return TypeRelation
case changesetMask:
return TypeChangeset
case noteMask:
return TypeNote
case userMask:
return TypeUser
case boundsMask:
return TypeBounds
}
panic("unknown type")
}
// Ref returns the ID reference for the object. Not unique without the type.
func (id ObjectID) Ref() int64 {
return int64((id & refMask) >> versionBits)
}
// Version returns the version of the object.
// Will return 0 if the object doesn't have versions like users, notes and changesets.
func (id ObjectID) Version() int {
return int(id & (versionMask))
}
// String returns "type/ref:version" for the object.
func (id ObjectID) String() string {
if id.Version() == 0 {
return fmt.Sprintf("%s/%d:-", id.Type(), id.Ref())
}
return fmt.Sprintf("%s/%d:%d", id.Type(), id.Ref(), id.Version())
}
// ParseObjectID takes a string and tries to determine the object id from it.
// The string must be formatted as "type/id:version", the same as the result of the String method.
func ParseObjectID(s string) (ObjectID, error) {
parts := strings.Split(s, "/")
if len(parts) != 2 {
return 0, fmt.Errorf("invalid element id: %v", s)
}
parts2 := strings.Split(parts[1], ":")
if l := len(parts2); l == 0 || l > 2 {
return 0, fmt.Errorf("invalid element id: %v", s)
}
var version int
ref, err := strconv.ParseInt(parts2[0], 10, 64)
if err != nil {
return 0, fmt.Errorf("invalid element id: %v: %v", s, err)
}
if len(parts2) == 2 && parts2[1] != "-" {
v, e := strconv.ParseInt(parts2[1], 10, 64)
if e != nil {
return 0, fmt.Errorf("invalid element id: %v: %v", s, err)
}
version = int(v)
}
oid, err := Type(parts[0]).objectID(ref, version)
if err != nil {
return 0, fmt.Errorf("invalid element id: %v: %v", s, err)
}
return oid, nil
}
// An Object represents a Node, Way, Relation, Changeset, Note or User only.
type Object interface {
ObjectID() ObjectID
// private is so that **ID types don't implement this interface.
private()
}
func (n *Node) private() {}
func (w *Way) private() {}
func (r *Relation) private() {}
func (c *Changeset) private() {}
func (n *Note) private() {}
func (u *User) private() {}
func (b *Bounds) private() {}
// Objects is a set of objects with some helpers
type Objects []Object
// ObjectIDs returns a slice of the object ids of the osm objects.
func (os Objects) ObjectIDs() ObjectIDs {
if len(os) == 0 {
return nil
}
ids := make(ObjectIDs, 0, len(os))
for _, o := range os {
ids = append(ids, o.ObjectID())
}
return ids
}
// ObjectIDs is a slice of ObjectIDs with some helpers on top.
type ObjectIDs []ObjectID
// A Scanner reads osm data from planet dump files.
// It is based on the bufio.Scanner, common usage.
// Scanners are not safe for parallel use. One should feed the
// objects into their own channel and have workers read from that.
//
// s := scanner.New(r)
// defer s.Close()
//
// for s.Next() {
// o := s.Object()
// // do something
// }
//
// if s.Err() != nil {
// // scanner did not complete fully
// }
type Scanner interface {
Scan() bool
Object() Object
Err() error
Close() error
}