You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: unmarshal.go
    path of file: ./repos/sealer/vendor/github.com/ipld/go-ipld-prime/codec/dagjson
    
    the code of the file until where you have to start completion: package dagjson

import (
	"encoding/base64"
	"fmt"
	"io"

	cid "github.com/ipfs/go-cid"
	"github.com/polydawn/refmt/json"
	"github.com/polydawn/refmt/shared"
	"github.com/polydawn/refmt/tok"

	"github.com/ipld/go-ipl
    
func (st *unmarshalState) unmarshal(na datamodel.NodeAssembler, tokSrc shared.TokenSource) error {
	// FUTURE: check for schema.TypedNodeBuilder that's going to parse a Link (they can slurp any token kind they want).
	switch st.tk[0].Type {
	case tok.TMapOpen:
		// dag-json has special needs: we pump a few tokens ahead to look for dag-json's "link" pattern.
		//  We can't actually call BeginMap until we're sure it's not gonna turn out to be a link.
		if st.options.ParseLinks {
			gotLink, err := st.linkLookahead(na, tokSrc)
			if err != nil { // return in error if any token peeks failed or if structure looked like a link but failed to parse as CID.
				return err
			}
			if gotLink {
				return nil
			}
		}

		if st.options.ParseBytes {
			gotBytes, err := st.bytesLookahead(na, tokSrc)
			if err != nil {
				return err
			}
			if gotBytes {
				return nil
			}
		}

		// Okay, now back to regularly scheduled map logic.
		ma, err := na.BeginMap(-1)
		if err != nil {
			return err
		}
		for {
			err := st.step(tokSrc) // shift next token into slot 0.
			if err != nil {        // return in error if next token unreadable
				return err
			}
			switch st.tk[0].Type {
			case tok.TMapClose:
				return ma.Finish()
			case tok.TString:
				// continue
			default:
				return fmt.Errorf("unexpected %s token while expecting map key", st.tk[0].Type)
			}
			mva, err := ma.AssembleEntry(st.tk[0].Str)
			if err != nil { // return in error if the key was rejected
				return err
			}
			// Do another shift so the next token is primed before we recurse.
			err = st.step(tokSrc)
			if err != nil { // return in error if next token unreadable
				return err
			}
			err = st.unmarshal(mva, tokSrc)
			if err != nil { // return in error if some part of the recursion errored
				return err
			}
		}
	case tok.TMapClose:
		return fmt.Errorf("unexpected mapClose token")
	case tok.TArrOpen:
		la, err := na.BeginList(-1)
		if err != nil {
			return err
		}
		for {
			_, err := tokSrc.Step(&st.tk[0])
			if err != nil {
				return err
			}
			switch st.tk[0].Type {
			case tok.TArrClose:
				return la.Finish()
			default:
				err := st.unmarshal(la.AssembleValue(), tokSrc)
				if err != nil { // return in error if some part of the recursion errored
					return err
				}
			}
		}
	case tok.TArrClose:
		return fmt.Errorf("unexpected arrClose token")
	case tok.TNull:
		return na.AssignNull()
	case tok.TString:
		return na.AssignString(st.tk[0].Str)
	case tok.TBytes:
		return na.AssignBytes(st.tk[0].Bytes)
	case tok.TBool:
		return na.AssignBool(st.tk[0].Bool)
	case tok.TInt:
		return na.AssignInt(st.tk[0].Int)
	case tok.TUint:
		return na.AssignInt(int64(st.tk[0].Uint)) // FIXME overflow check
	case tok.TFloat64:
		return na.AssignFloat(st.tk[0].Float64)
	default:
		panic("unreachable")
	}
}