github.com/joomcode/cue@v0.4.4-0.20221111115225-539fe3512047/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 "github.com/joomcode/cue/cue/build" 22 "github.com/joomcode/cue/cue/errors" 23 "github.com/joomcode/cue/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 // These are initialized during Go package initialization time and do not 69 // need to be guarded. 70 builtinPaths map[string]PackageFunc // Full path 71 builtinShort map[string]string // Commandline shorthand 72 73 typeCache sync.Map // map[reflect.Type]evaluated 74 } 75 76 func newIndex() *index { 77 i := &index{ 78 imports: map[*adt.Vertex]*build.Instance{}, 79 importsByPath: map[string]*adt.Vertex{}, 80 importsByBuild: map[*build.Instance]*adt.Vertex{}, 81 } 82 return i 83 } 84 85 func (x *index) shortBuiltinToPath(id string) string { 86 if x == nil || x.builtinPaths == nil { 87 return "" 88 } 89 return x.builtinShort[id] 90 } 91 92 func (r *Runtime) AddInst(path string, key *adt.Vertex, p *build.Instance) { 93 r.index.lock.Lock() 94 defer r.index.lock.Unlock() 95 96 x := r.index 97 if key == nil { 98 panic("key must not be nil") 99 } 100 x.imports[key] = p 101 x.importsByBuild[p] = key 102 if path != "" { 103 x.importsByPath[path] = key 104 } 105 } 106 107 func (r *Runtime) GetInstanceFromNode(key *adt.Vertex) *build.Instance { 108 r.index.lock.RLock() 109 defer r.index.lock.RUnlock() 110 111 return r.index.imports[key] 112 } 113 114 func (r *Runtime) getNodeFromInstance(key *build.Instance) *adt.Vertex { 115 r.index.lock.RLock() 116 defer r.index.lock.RUnlock() 117 118 return r.index.importsByBuild[key] 119 } 120 121 func (r *Runtime) LoadImport(importPath string) *adt.Vertex { 122 r.index.lock.Lock() 123 defer r.index.lock.Unlock() 124 125 x := r.index 126 127 key := x.importsByPath[importPath] 128 if key != nil { 129 return key 130 } 131 132 if x.builtinPaths != nil { 133 if f := x.builtinPaths[importPath]; f != nil { 134 p, err := f(r) 135 if err != nil { 136 return adt.ToVertex(&adt.Bottom{Err: err}) 137 } 138 inst := &build.Instance{ 139 ImportPath: importPath, 140 PkgName: path.Base(importPath), 141 } 142 x.imports[p] = inst 143 x.importsByPath[importPath] = p 144 x.importsByBuild[inst] = p 145 return p 146 } 147 } 148 149 return key 150 }