decode.go builds without C or unsafe.
diff --git a/api_c.go b/api_c.go
index 5d7a0f0..3212d0b 100644
--- a/api_c.go
+++ b/api_c.go
@@ -98,6 +98,11 @@
 	return true
 }
 
+// Destroy a parser object.
+func yaml_parser_delete(parser *yaml_parser_t) {
+    *parser = yaml_parser_t{}
+}
+
 // String read handler.
 func yaml_string_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) {
 	if parser.input_pos == len(parser.input) {
@@ -794,6 +799,11 @@
 //    return 1;
 //}
 
+// Destroy an event object.
+func yaml_event_delete(event *yaml_event_t) {
+	*event = yaml_event_t{}
+}
+
 ///*
 // * Create a document object.
 // */
diff --git a/decode.go b/decode.go
index b03f36e..6179e66 100644
--- a/decode.go
+++ b/decode.go
@@ -1,16 +1,8 @@
 package goyaml
 
-// #cgo LDFLAGS: -lm -lpthread
-// #cgo windows CFLAGS: -DYAML_DECLARE_STATIC=1 -Dstrdup=_strdup
-// #cgo CFLAGS: -I. -DHAVE_CONFIG_H=1
-//
-// #include "helpers.h"
-import "C"
-
 import (
 	"reflect"
 	"strconv"
-	"unsafe"
 )
 
 const (
@@ -31,22 +23,18 @@
 	anchors      map[string]*node
 }
 
-func stry(s *C.yaml_char_t) string {
-	return C.GoString((*C.char)(unsafe.Pointer(s)))
-}
-
 // ----------------------------------------------------------------------------
 // Parser, produces a node tree out of a libyaml event stream.
 
 type parser struct {
-	parser C.yaml_parser_t
-	event  C.yaml_event_t
+	parser yaml_parser_t
+	event  yaml_event_t
 	doc    *node
 }
 
 func newParser(b []byte) *parser {
 	p := parser{}
-	if C.yaml_parser_initialize(&p.parser) == 0 {
+	if !yaml_parser_initialize(&p.parser) {
 		panic("Failed to initialize YAML emitter")
 	}
 
@@ -54,35 +42,31 @@
 		b = []byte{'\n'}
 	}
 
-	// How unsafe is this really?  Will this break if the GC becomes compacting?
-	// Probably not, otherwise that would likely break &parse below as well.
-	input := (*C.uchar)(unsafe.Pointer(&b[0]))
-	C.yaml_parser_set_input_string(&p.parser, input, (C.size_t)(len(b)))
+	yaml_parser_set_input_string(&p.parser, b)
 
 	p.skip()
-	if p.event._type != C.YAML_STREAM_START_EVENT {
-		panic("Expected stream start event, got " +
-			strconv.Itoa(int(p.event._type)))
+	if p.event.typ != yaml_STREAM_START_EVENT {
+		panic("Expected stream start event, got " + strconv.Itoa(int(p.event.typ)))
 	}
 	p.skip()
 	return &p
 }
 
 func (p *parser) destroy() {
-	if p.event._type != C.YAML_NO_EVENT {
-		C.yaml_event_delete(&p.event)
+	if p.event.typ != yaml_NO_EVENT {
+		yaml_event_delete(&p.event)
 	}
-	C.yaml_parser_delete(&p.parser)
+	yaml_parser_delete(&p.parser)
 }
 
 func (p *parser) skip() {
-	if p.event._type != C.YAML_NO_EVENT {
-		if p.event._type == C.YAML_STREAM_END_EVENT {
+	if p.event.typ != yaml_NO_EVENT {
+		if p.event.typ == yaml_STREAM_END_EVENT {
 			panic("Attempted to go past the end of stream. Corrupted value?")
 		}
-		C.yaml_event_delete(&p.event)
+		yaml_event_delete(&p.event)
 	}
-	if C.yaml_parser_parse(&p.parser, &p.event) == 0 {
+	if !yaml_parser_parse(&p.parser, &p.event) {
 		p.fail()
 	}
 }
@@ -91,54 +75,56 @@
 	var where string
 	var line int
 	if p.parser.problem_mark.line != 0 {
-		line = int(C.int(p.parser.problem_mark.line))
+		line = p.parser.problem_mark.line
 	} else if p.parser.context_mark.line != 0 {
-		line = int(C.int(p.parser.context_mark.line))
+		line = p.parser.context_mark.line
 	}
 	if line != 0 {
 		where = "line " + strconv.Itoa(line) + ": "
 	}
 	var msg string
-	if p.parser.problem != nil {
-		msg = C.GoString(p.parser.problem)
+	if len(p.parser.problem) > 0 {
+		msg = p.parser.problem
 	} else {
 		msg = "Unknown problem parsing YAML content"
 	}
 	panic(where + msg)
 }
 
-func (p *parser) anchor(n *node, anchor *C.yaml_char_t) {
+func (p *parser) anchor(n *node, anchor []byte) {
 	if anchor != nil {
-		p.doc.anchors[stry(anchor)] = n
+		p.doc.anchors[string(anchor)] = n
 	}
 }
 
 func (p *parser) parse() *node {
-	switch p.event._type {
-	case C.YAML_SCALAR_EVENT:
+	switch p.event.typ {
+	case yaml_SCALAR_EVENT:
 		return p.scalar()
-	case C.YAML_ALIAS_EVENT:
+	case yaml_ALIAS_EVENT:
 		return p.alias()
-	case C.YAML_MAPPING_START_EVENT:
+	case yaml_MAPPING_START_EVENT:
 		return p.mapping()
-	case C.YAML_SEQUENCE_START_EVENT:
+	case yaml_SEQUENCE_START_EVENT:
 		return p.sequence()
-	case C.YAML_DOCUMENT_START_EVENT:
+	case yaml_DOCUMENT_START_EVENT:
 		return p.document()
-	case C.YAML_STREAM_END_EVENT:
+	case yaml_STREAM_END_EVENT:
 		// Happens when attempting to decode an empty buffer.
 		return nil
 	default:
 		panic("Attempted to parse unknown event: " +
-			strconv.Itoa(int(p.event._type)))
+			strconv.Itoa(int(p.event.typ)))
 	}
 	panic("Unreachable")
 }
 
 func (p *parser) node(kind int) *node {
-	return &node{kind: kind,
-		line:   int(C.int(p.event.start_mark.line)),
-		column: int(C.int(p.event.start_mark.column))}
+	return &node{
+		kind:   kind,
+		line:   p.event.start_mark.line,
+		column: p.event.start_mark.column,
+	}
 }
 
 func (p *parser) document() *node {
@@ -147,28 +133,27 @@
 	p.doc = n
 	p.skip()
 	n.children = append(n.children, p.parse())
-	if p.event._type != C.YAML_DOCUMENT_END_EVENT {
+	if p.event.typ != yaml_DOCUMENT_END_EVENT {
 		panic("Expected end of document event but got " +
-			strconv.Itoa(int(p.event._type)))
+			strconv.Itoa(int(p.event.typ)))
 	}
 	p.skip()
 	return n
 }
 
 func (p *parser) alias() *node {
-	alias := C.event_alias(&p.event)
 	n := p.node(aliasNode)
-	n.value = stry(alias.anchor)
+	n.value = string(p.event.alias.anchor)
 	p.skip()
 	return n
 }
 
 func (p *parser) scalar() *node {
-	scalar := C.event_scalar(&p.event)
+	scalar := p.event.scalar
 	n := p.node(scalarNode)
-	n.value = stry(scalar.value)
-	n.tag = stry(scalar.tag)
-	n.implicit = (scalar.plain_implicit != 0)
+	n.value = string(scalar.value)
+	n.tag = string(scalar.tag)
+	n.implicit = scalar.plain_implicit
 	p.anchor(n, scalar.anchor)
 	p.skip()
 	return n
@@ -176,9 +161,9 @@
 
 func (p *parser) sequence() *node {
 	n := p.node(sequenceNode)
-	p.anchor(n, C.event_sequence_start(&p.event).anchor)
+	p.anchor(n, p.event.sequence_start.anchor)
 	p.skip()
-	for p.event._type != C.YAML_SEQUENCE_END_EVENT {
+	for p.event.typ != yaml_SEQUENCE_END_EVENT {
 		n.children = append(n.children, p.parse())
 	}
 	p.skip()
@@ -187,9 +172,9 @@
 
 func (p *parser) mapping() *node {
 	n := p.node(mappingNode)
-	p.anchor(n, C.event_mapping_start(&p.event).anchor)
+	p.anchor(n, p.event.mapping_start.anchor)
 	p.skip()
-	for p.event._type != C.YAML_MAPPING_END_EVENT {
+	for p.event.typ != yaml_MAPPING_END_EVENT {
 		n.children = append(n.children, p.parse(), p.parse())
 	}
 	p.skip()
diff --git a/encode.go b/encode.go
index c7fcdb2..e6375e2 100644
--- a/encode.go
+++ b/encode.go
@@ -1,5 +1,9 @@
 package goyaml
 
+// #cgo LDFLAGS: -lm -lpthread
+// #cgo windows CFLAGS: -DYAML_DECLARE_STATIC=1 -Dstrdup=_strdup
+// #cgo CFLAGS: -I. -DHAVE_CONFIG_H=1
+//
 // #include "helpers.h"
 import "C"