File: a__importer.go

package info (click to toggle)
golang-github-bep-golibsass 1.1.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,840 kB
  • sloc: cpp: 30,477; ansic: 848; sh: 662; makefile: 344; perl: 124
file content (110 lines) | stat: -rw-r--r-- 2,625 bytes parent folder | download
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
// Copyright © 2020 Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>.
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
package libsass

// #include <stdint.h>
// #include "sass/context.h"
//
// extern struct Sass_Import** BridgeImport(const char* currPath, const char* prevPath, int i);
//
// Sass_Import_List SassImport(const char* currPath, Sass_Importer_Entry imp, struct Sass_Compiler* comp)
// {
//   void* c = sass_importer_get_cookie(imp);
//   uintptr_t ci = (uintptr_t)c;
//   struct Sass_Import* prevPath = sass_compiler_get_last_import(comp);
//   const char* prev_path = sass_import_get_imp_path(prevPath);
//   return BridgeImport(currPath, prev_path, ci);
// }
import "C"

import (
	"sync"
	"unsafe"
)

const uintptrOffset = 4096 // the smallest legal pointer

var importsStore = &idMap{
	m: make(map[int]interface{}),
	i: uintptrOffset,
}

// AddImportResolver adds a function to resolve imports in LibSASS.
// Make sure to run call DeleteImportResolver when done.
//
//go:nocheckptr
func AddImportResolver(opts SassOptions, resolver ImportResolver) int {
	i := importsStore.Set(resolver)
	// This looks unsafe, but LibSass is using void* to store an int.
	// TODO(bep) this prevents us from "fail on go vet errors" in GitHub action.
	id := unsafe.Pointer(uintptr(i))

	importers := C.sass_make_importer_list(1)
	C.sass_importer_set_list_entry(
		importers,
		0,
		C.sass_make_importer(
			C.Sass_Importer_Fn(C.SassImport),
			C.double(0),
			id,
		),
	)

	C.sass_option_set_c_importers(
		(*C.struct_Sass_Options)(unsafe.Pointer(opts)),
		importers,
	)

	return i
}

func DeleteImportResolver(i int) error {
	importsStore.Delete(i)
	return nil
}

// ImportResolver can be used as a custom import resolver.
// Return an empty body to load the import body from the path.
// See AddImportResolver.
type ImportResolver func(currPath string, prevPath string) (newPath string, body string, resolved bool)

type idMap struct {
	sync.RWMutex
	m       map[int]interface{}
	i       int
	idStack []int
}

func (m *idMap) Delete(i int) {
	m.Lock()
	defer m.Unlock()
	m.idStack = append(m.idStack, i)
	delete(m.m, i)
}

func (m *idMap) Get(i int) interface{} {
	m.RLock()
	defer m.RUnlock()
	return m.m[i]
}

func (m *idMap) nextID() (id int) {
	if len(m.idStack) == 0 {
		for i := 1; i <= 50; i++ {
			m.idStack = append(m.idStack, m.i+i)
		}
		m.i += 50
	}
	id, m.idStack = m.idStack[len(m.idStack)-1], m.idStack[:len(m.idStack)-1]
	return
}

func (m *idMap) Set(v interface{}) int {
	m.Lock()
	defer m.Unlock()
	id := m.nextID()
	m.m[id] = v
	return id
}