Skip to content

Commit

Permalink
all: add backward support for Go 1.16 (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
changkun authored Sep 22, 2021
1 parent 08b9d79 commit 10ba29a
Show file tree
Hide file tree
Showing 18 changed files with 350 additions and 16 deletions.
11 changes: 6 additions & 5 deletions .github/workflows/clipboard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
go: [ '1.16.x', '1.17.x' ]
steps:
- name: Install and run dependencies (xvfb libx11-dev)
if: ${{ runner.os == 'Linux' }}
Expand All @@ -47,24 +48,24 @@ jobs:
- uses: actions/setup-go@v2
with:
stable: 'false'
go-version: '1.17.x'
go-version: ${{ matrix.go }}

- name: Build
- name: Build (${{ matrix.go }})
run: |
go build -o gclip cmd/gclip/main.go
go build -o gclip-gui cmd/gclip-gui/main.go
- name: Run Tests with CGO_ENABLED=1
- name: Run Tests with CGO_ENABLED=1 (${{ matrix.go }})
if: ${{ runner.os == 'Linux' || runner.os == 'macOS'}}
run: |
CGO_ENABLED=1 go test -v -covermode=atomic .
- name: Run Tests with CGO_ENABLED=0
- name: Run Tests with CGO_ENABLED=0 (${{ matrix.go }})
if: ${{ runner.os == 'Linux' || runner.os == 'macOS'}}
run: |
CGO_ENABLED=0 go test -v -covermode=atomic .
- name: Run Tests on Windows
- name: Run Tests on Windows (${{ matrix.go }})
if: ${{ runner.os == 'Windows'}}
run: |
go test -v -covermode=atomic .
1 change: 1 addition & 0 deletions clipboard_android.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Written by Changkun Ou <changkun.de>

//go:build android
// +build android

#include <android/log.h>
#include <jni.h>
Expand Down
1 change: 1 addition & 0 deletions clipboard_android.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Written by Changkun Ou <changkun.de>

//go:build android
// +build android

package clipboard

Expand Down
1 change: 1 addition & 0 deletions clipboard_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Written by Changkun Ou <changkun.de>

//go:build darwin && !ios
// +build darwin,!ios

package clipboard

Expand Down
1 change: 1 addition & 0 deletions clipboard_darwin.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Written by Changkun Ou <changkun.de>

//go:build darwin && !ios
// +build darwin,!ios

// Interact with NSPasteboard using Objective-C
// https://developer.apple.com/documentation/appkit/nspasteboard?language=objc
Expand Down
1 change: 1 addition & 0 deletions clipboard_ios.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Written by Changkun Ou <changkun.de>

//go:build ios
// +build ios

package clipboard

Expand Down
1 change: 1 addition & 0 deletions clipboard_ios.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Written by Changkun Ou <changkun.de>

//go:build ios
// +build ios

#import <UIKit/UIKit.h>
#import <MobileCoreServices/MobileCoreServices.h>
Expand Down
1 change: 1 addition & 0 deletions clipboard_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Written by Changkun Ou <changkun.de>

//go:build linux && !android
// +build linux,!android

#include <stdlib.h>
#include <stdio.h>
Expand Down
4 changes: 3 additions & 1 deletion clipboard_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Written by Changkun Ou <changkun.de>

//go:build linux && !android
// +build linux,!android

package clipboard

Expand Down Expand Up @@ -34,9 +35,10 @@ import (
"fmt"
"os"
"runtime"
"runtime/cgo"
"time"
"unsafe"

"golang.design/x/clipboard/internal/cgo"
)

const errmsg = `Failed to initialize the X11 display, and the clipboard package
Expand Down
1 change: 1 addition & 0 deletions clipboard_nocgo.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//go:build !windows && !cgo
// +build !windows,!cgo

package clipboard

Expand Down
1 change: 1 addition & 0 deletions clipboard_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Written by Changkun Ou <changkun.de>

//go:build windows
// +build windows

package clipboard

Expand Down
1 change: 1 addition & 0 deletions cmd/gclip-gui/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Written by Changkun Ou <changkun.de>

//go:build android || ios || linux || darwin || windows
// +build android ios linux darwin windows

// This is a very basic example for verification purpose that
// demonstrates how the golang.design/x/clipboard can interact
Expand Down
1 change: 1 addition & 0 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Written by Changkun Ou <changkun.de>

//go:build cgo
// +build cgo

package clipboard_test

Expand Down
7 changes: 1 addition & 6 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
module golang.design/x/clipboard

go 1.17
go 1.16

require (
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d
golang.org/x/mobile v0.0.0-20210716004757-34ab1303b554
)

require (
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 // indirect
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect
)
159 changes: 159 additions & 0 deletions internal/cgo/handle.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
// Copyright 2021 The golang.design Initiative Authors.
// All rights reserved. Use of this source code is governed
// by a MIT license that can be found in the LICENSE file.
//
// Written by Changkun Ou <changkun.de>

//go:build !go1.17
// +build !go1.17

// Package cgo is an implementation of golang.org/issue/37033.
//
// See golang.org/cl/294670 for code review discussion.
package cgo

import (
"reflect"
"sync"
)

// Handle provides a safe representation to pass Go values between C and
// Go back and forth. The zero value of a handle is not a valid handle,
// and thus safe to use as a sentinel in C APIs.
//
// The underlying type of Handle may change, but the value is guaranteed
// to fit in an integer type that is large enough to hold the bit pattern
// of any pointer. For instance, on the Go side:
//
// package main
//
// /*
// extern void MyGoPrint(unsigned long long handle);
// void myprint(unsigned long long handle);
// */
// import "C"
// import "runtime/cgo"
//
// //export MyGoPrint
// func MyGoPrint(handle C.ulonglong) {
// h := cgo.Handle(handle)
// val := h.Value().(int)
// println(val)
// h.Delete()
// }
//
// func main() {
// val := 42
// C.myprint(C.ulonglong(cgo.NewHandle(val)))
// // Output: 42
// }
//
// and on the C side:
//
// // A Go function
// extern void MyGoPrint(unsigned long long handle);
//
// // A C function
// void myprint(unsigned long long handle) {
// MyGoPrint(handle);
// }
type Handle uintptr

// NewHandle returns a handle for a given value. If a given value is a
// pointer, slice, map, channel, or function that refers to the same
// object, the returned handle will also be the same. Besides, nil value
// must not be used.
//
// The handle is valid until the program calls Delete on it. The handle
// uses resources, and this package assumes that C code may hold on to
// the handle, so a program must explicitly call Delete when the handle
// is no longer needed.
//
// The intended use is to pass the returned handle to C code, which
// passes it back to Go, which calls Value. See an example in the
// comments of the Handle definition.
func NewHandle(v interface{}) Handle {
var k uintptr

rv := reflect.ValueOf(v)
switch rv.Kind() {
case reflect.Ptr, reflect.UnsafePointer, reflect.Slice,
reflect.Map, reflect.Chan, reflect.Func:
if rv.IsNil() {
panic("cgo: cannot use Handle for nil value")
}

k = rv.Pointer()
default:
// Wrap and turn a value parameter into a pointer. This enables
// us to always store the passing object as a pointer, and helps
// to identify which of whose are initially pointers or values
// when Value is called.
v = &wrap{v}
k = reflect.ValueOf(v).Pointer()
}

// v was escaped to the heap because of reflection. As Go do not have
// a moving GC (and possibly lasts true for a long future), it is
// safe to use its pointer address as the key of the global map at
// this moment. The implementation must be reconsidered if moving GC
// is introduced internally in the runtime.
actual, loaded := m.LoadOrStore(k, v)
if !loaded {
return Handle(k)
}

arv := reflect.ValueOf(actual)
switch arv.Kind() {
case reflect.Ptr, reflect.UnsafePointer, reflect.Slice,
reflect.Map, reflect.Chan, reflect.Func:
// The underlying object of the given Go value already have
// its existing handle.
if arv.Pointer() == k {
return Handle(k)
}

// If the loaded pointer is inconsistent with the new pointer,
// it means the address has been used for different objects
// because of GC and its address is reused for a new Go object,
// meaning that the Handle does not call Delete explicitly when
// the old Go value is not needed. Consider this as a misuse of
// a handle, do panic.
panic("cgo: misuse of a Handle")
default:
panic("cgo: Handle implementation has an internal bug")
}
}

// Delete invalidates a handle. This method must be called when C code no
// longer has a copy of the handle, and the program no longer needs the
// Go value that associated with the handle.
//
// The method panics if the handle is invalid already.
func (h Handle) Delete() {
_, ok := m.LoadAndDelete(uintptr(h))
if !ok {
panic("cgo: misuse of an invalid Handle")
}
}

// Value returns the associated Go value for a valid handle.
//
// The method panics if the handle is invalid already.
func (h Handle) Value() interface{} {
v, ok := m.Load(uintptr(h))
if !ok {
panic("cgo: misuse of an invalid Handle")
}
if wv, ok := v.(*wrap); ok {
return wv.v
}
return v
}

var m = &sync.Map{} // map[uintptr]interface{}

// wrap wraps a Go value.
type wrap struct {
v interface{}
}
16 changes: 16 additions & 0 deletions internal/cgo/handle_117.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2021 The golang.design Initiative Authors.
// All rights reserved. Use of this source code is governed
// by a MIT license that can be found in the LICENSE file.
//
// Written by Changkun Ou <changkun.de>

//go:build go1.17
// +build go1.17

package cgo

import "runtime/cgo"

type Handle = cgo.Handle

var NewHandle = cgo.NewHandle
Loading

0 comments on commit 10ba29a

Please sign in to comment.