cuelang.org/go@v0.10.1/internal/core/runtime/imports.go (about) 1 // Copyright 2020 CUE Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package runtime 16 17 import ( 18 "path" 19 "sync" 20 21 "cuelang.org/go/cue/build" 22 "cuelang.org/go/cue/errors" 23 "cuelang.org/go/internal/core/adt" 24 ) 25 26 type PackageFunc func(ctx adt.Runtime) (*adt.Vertex, errors.Error) 27 28 func RegisterBuiltin(importPath string, f PackageFunc) { 29 sharedIndex.RegisterBuiltin(importPath, f) 30 } 31 32 func (x *index) RegisterBuiltin(importPath string, f PackageFunc) { 33 if x.builtinPaths == nil { 34 x.builtinPaths = map[string]PackageFunc{} 35 x.builtinShort = map[string]string{} 36 } 37 x.builtinPaths[importPath] = f 38 base := path.Base(importPath) 39 if _, ok := x.builtinShort[base]; ok { 40 importPath = "" // Don't allow ambiguous base paths. 41 } 42 x.builtinShort[base] = importPath 43 } 44 45 var SharedRuntime = &Runtime{index: sharedIndex} 46 47 // BuiltinPackagePath converts a short-form builtin package identifier to its 48 // full path or "" if this doesn't exist. 49 func (x *Runtime) BuiltinPackagePath(path string) string { 50 return x.index.shortBuiltinToPath(path) 51 } 52 53 // sharedIndex is used for indexing builtins and any other labels common to 54 // all instances. 55 var sharedIndex = newIndex() 56 57 // index maps conversions from label names to internal codes. 58 // 59 // All instances belonging to the same package should share this index. 60 type index struct { 61 // lock is used to guard imports-related maps. 62 // TODO: makes these per cuecontext. 63 lock sync.RWMutex 64 imports map[*adt.Vertex]*build.Instance 65 importsByPath map[string]*adt.Vertex 66 importsByBuild map[*build.Instance]*adt.Vertex 67 68 nextUniqueID uint64 69 70 // These are initialized during Go package initialization time and do not 71 // need to be guarded. 72 builtinPaths map[string]PackageFunc // Full path 73 builtinShort map[string]string // Commandline shorthand 74 75 typeCache sync.Map // map[reflect.Type]evaluated 76 } 77 78 func (i *index) getNextUniqueID() uint64 { 79 // TODO: use atomic increment instead. 80 i.lock.Lock() 81 i.nextUniqueID++ 82 x := i.nextUniqueID 83 i.lock.Unlock() 84 return x 85 } 86 87 func newIndex() *index { 88 i := &index{ 89 imports: map[*adt.Vertex]*build.Instance{}, 90 importsByPath: map[string]*adt.Vertex{}, 91 importsByBuild: map[*build.Instance]*adt.Vertex{}, 92 } 93 return i 94 } 95 96 func (x *index) shortBuiltinToPath(id string) string { 97 if x == nil || x.builtinPaths == nil { 98 return "" 99 } 100 return x.builtinShort[id] 101 } 102 103 func (r *Runtime) AddInst(path string, key *adt.Vertex, p *build.Instance) { 104 r.index.lock.Lock() 105 defer r.index.lock.Unlock() 106 107 x := r.index 108 if key == nil { 109 panic("key must not be nil") 110 } 111 x.imports[key] = p 112 x.importsByBuild[p] = key 113 if path != "" { 114 x.importsByPath[path] = key 115 } 116 } 117 118 func (r *Runtime) GetInstanceFromNode(key *adt.Vertex) *build.Instance { 119 r.index.lock.RLock() 120 defer r.index.lock.RUnlock() 121 122 return r.index.imports[key] 123 } 124 125 func (r *Runtime) getNodeFromInstance(key *build.Instance) *adt.Vertex { 126 r.index.lock.RLock() 127 defer r.index.lock.RUnlock() 128 129 return r.index.importsByBuild[key] 130 } 131 132 func (r *Runtime) LoadImport(importPath string) *adt.Vertex { 133 r.index.lock.Lock() 134 defer r.index.lock.Unlock() 135 136 x := r.index 137 138 key := x.importsByPath[importPath] 139 if key != nil { 140 return key 141 } 142 143 if x.builtinPaths != nil { 144 if f := x.builtinPaths[importPath]; f != nil { 145 p, err := f(r) 146 if err != nil { 147 return adt.ToVertex(&adt.Bottom{Err: err}) 148 } 149 inst := &build.Instance{ 150 ImportPath: importPath, 151 PkgName: path.Base(importPath), 152 } 153 x.imports[p] = inst 154 x.importsByPath[importPath] = p 155 x.importsByBuild[inst] = p 156 return p 157 } 158 } 159 160 return key 161 }