github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/pkg/marshal/primitive/primitive.go (about)

     1  // Copyright 2020 The gVisor 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 primitive defines marshal.Marshallable implementations for primitive
    16  // types.
    17  package primitive
    18  
    19  import (
    20  	"io"
    21  
    22  	"github.com/metacubex/gvisor/pkg/hostarch"
    23  	"github.com/metacubex/gvisor/pkg/marshal"
    24  )
    25  
    26  // Int8 is a marshal.Marshallable implementation for int8.
    27  //
    28  // +marshal boundCheck slice:Int8Slice:inner
    29  type Int8 int8
    30  
    31  // Uint8 is a marshal.Marshallable implementation for uint8.
    32  //
    33  // +marshal boundCheck slice:Uint8Slice:inner
    34  type Uint8 uint8
    35  
    36  // Int16 is a marshal.Marshallable implementation for int16.
    37  //
    38  // +marshal boundCheck slice:Int16Slice:inner
    39  type Int16 int16
    40  
    41  // Uint16 is a marshal.Marshallable implementation for uint16.
    42  //
    43  // +marshal boundCheck slice:Uint16Slice:inner
    44  type Uint16 uint16
    45  
    46  // Int32 is a marshal.Marshallable implementation for int32.
    47  //
    48  // +marshal boundCheck slice:Int32Slice:inner
    49  type Int32 int32
    50  
    51  // Uint32 is a marshal.Marshallable implementation for uint32.
    52  //
    53  // +marshal boundCheck slice:Uint32Slice:inner
    54  type Uint32 uint32
    55  
    56  // Int64 is a marshal.Marshallable implementation for int64.
    57  //
    58  // +marshal boundCheck slice:Int64Slice:inner
    59  type Int64 int64
    60  
    61  // Uint64 is a marshal.Marshallable implementation for uint64.
    62  //
    63  // +marshal boundCheck slice:Uint64Slice:inner
    64  type Uint64 uint64
    65  
    66  // ByteSlice is a marshal.Marshallable implementation for []byte.
    67  // This is a convenience wrapper around a dynamically sized type, and can't be
    68  // embedded in other marshallable types because it breaks assumptions made by
    69  // go-marshal internals. It violates the "no dynamically-sized types"
    70  // constraint of the go-marshal library.
    71  type ByteSlice []byte
    72  
    73  // SizeBytes implements marshal.Marshallable.SizeBytes.
    74  func (b *ByteSlice) SizeBytes() int {
    75  	return len(*b)
    76  }
    77  
    78  // MarshalBytes implements marshal.Marshallable.MarshalBytes.
    79  func (b *ByteSlice) MarshalBytes(dst []byte) []byte {
    80  	return dst[copy(dst, *b):]
    81  }
    82  
    83  // UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
    84  func (b *ByteSlice) UnmarshalBytes(src []byte) []byte {
    85  	return src[copy(*b, src):]
    86  }
    87  
    88  // Packed implements marshal.Marshallable.Packed.
    89  func (b *ByteSlice) Packed() bool {
    90  	return false
    91  }
    92  
    93  // MarshalUnsafe implements marshal.Marshallable.MarshalUnsafe.
    94  func (b *ByteSlice) MarshalUnsafe(dst []byte) []byte {
    95  	return b.MarshalBytes(dst)
    96  }
    97  
    98  // UnmarshalUnsafe implements marshal.Marshallable.UnmarshalUnsafe.
    99  func (b *ByteSlice) UnmarshalUnsafe(src []byte) []byte {
   100  	return b.UnmarshalBytes(src)
   101  }
   102  
   103  // CopyIn implements marshal.Marshallable.CopyIn.
   104  func (b *ByteSlice) CopyIn(cc marshal.CopyContext, addr hostarch.Addr) (int, error) {
   105  	return cc.CopyInBytes(addr, *b)
   106  }
   107  
   108  // CopyInN implements marshal.Marshallable.CopyInN.
   109  func (b *ByteSlice) CopyInN(cc marshal.CopyContext, addr hostarch.Addr, limit int) (int, error) {
   110  	return cc.CopyInBytes(addr, (*b)[:limit])
   111  }
   112  
   113  // CopyOut implements marshal.Marshallable.CopyOut.
   114  func (b *ByteSlice) CopyOut(cc marshal.CopyContext, addr hostarch.Addr) (int, error) {
   115  	return cc.CopyOutBytes(addr, *b)
   116  }
   117  
   118  // CopyOutN implements marshal.Marshallable.CopyOutN.
   119  func (b *ByteSlice) CopyOutN(cc marshal.CopyContext, addr hostarch.Addr, limit int) (int, error) {
   120  	return cc.CopyOutBytes(addr, (*b)[:limit])
   121  }
   122  
   123  // WriteTo implements io.WriterTo.WriteTo.
   124  func (b *ByteSlice) WriteTo(w io.Writer) (int64, error) {
   125  	n, err := w.Write(*b)
   126  	return int64(n), err
   127  }
   128  
   129  var _ marshal.Marshallable = (*ByteSlice)(nil)
   130  
   131  // The following set of functions are convenient shorthands for wrapping a
   132  // built-in type in a marshallable primitive type. For example:
   133  //
   134  // func useMarshallable(m marshal.Marshallable) { ... }
   135  //
   136  // // Compare:
   137  //
   138  // buf = []byte{...}
   139  // // useMarshallable(&primitive.ByteSlice(buf)) // Not allowed, can't address temp value.
   140  // bufP := primitive.ByteSlice(buf)
   141  // useMarshallable(&bufP)
   142  //
   143  // // Vs:
   144  //
   145  // useMarshallable(AsByteSlice(buf))
   146  //
   147  // Note that the argument to these function escapes, so avoid using them on very
   148  // hot code paths. But generally if a function accepts an interface as an
   149  // argument, the argument escapes anyways.
   150  
   151  // AllocateInt8 returns x as a marshallable.
   152  func AllocateInt8(x int8) marshal.Marshallable {
   153  	p := Int8(x)
   154  	return &p
   155  }
   156  
   157  // AllocateUint8 returns x as a marshallable.
   158  func AllocateUint8(x uint8) marshal.Marshallable {
   159  	p := Uint8(x)
   160  	return &p
   161  }
   162  
   163  // AllocateInt16 returns x as a marshallable.
   164  func AllocateInt16(x int16) marshal.Marshallable {
   165  	p := Int16(x)
   166  	return &p
   167  }
   168  
   169  // AllocateUint16 returns x as a marshallable.
   170  func AllocateUint16(x uint16) marshal.Marshallable {
   171  	p := Uint16(x)
   172  	return &p
   173  }
   174  
   175  // AllocateInt32 returns x as a marshallable.
   176  func AllocateInt32(x int32) marshal.Marshallable {
   177  	p := Int32(x)
   178  	return &p
   179  }
   180  
   181  // AllocateUint32 returns x as a marshallable.
   182  func AllocateUint32(x uint32) marshal.Marshallable {
   183  	p := Uint32(x)
   184  	return &p
   185  }
   186  
   187  // AllocateInt64 returns x as a marshallable.
   188  func AllocateInt64(x int64) marshal.Marshallable {
   189  	p := Int64(x)
   190  	return &p
   191  }
   192  
   193  // AllocateUint64 returns x as a marshallable.
   194  func AllocateUint64(x uint64) marshal.Marshallable {
   195  	p := Uint64(x)
   196  	return &p
   197  }
   198  
   199  // AsByteSlice returns b as a marshallable. Note that this allocates a new slice
   200  // header, but does not copy the slice contents.
   201  func AsByteSlice(b []byte) marshal.Marshallable {
   202  	bs := ByteSlice(b)
   203  	return &bs
   204  }
   205  
   206  // Below, we define some convenience functions for marshalling primitive types
   207  // using the newtypes above, without requiring superfluous casts.
   208  
   209  // 8-bit integers
   210  
   211  // CopyInt8In is a convenient wrapper for copying in an int8 from the task's
   212  // memory.
   213  func CopyInt8In(cc marshal.CopyContext, addr hostarch.Addr, dst *int8) (int, error) {
   214  	var buf Int8
   215  	n, err := buf.CopyIn(cc, addr)
   216  	if err != nil {
   217  		return n, err
   218  	}
   219  	*dst = int8(buf)
   220  	return n, nil
   221  }
   222  
   223  // CopyInt8Out is a convenient wrapper for copying out an int8 to the task's
   224  // memory.
   225  func CopyInt8Out(cc marshal.CopyContext, addr hostarch.Addr, src int8) (int, error) {
   226  	srcP := Int8(src)
   227  	return srcP.CopyOut(cc, addr)
   228  }
   229  
   230  // CopyUint8In is a convenient wrapper for copying in a uint8 from the task's
   231  // memory.
   232  func CopyUint8In(cc marshal.CopyContext, addr hostarch.Addr, dst *uint8) (int, error) {
   233  	var buf Uint8
   234  	n, err := buf.CopyIn(cc, addr)
   235  	if err != nil {
   236  		return n, err
   237  	}
   238  	*dst = uint8(buf)
   239  	return n, nil
   240  }
   241  
   242  // CopyUint8Out is a convenient wrapper for copying out a uint8 to the task's
   243  // memory.
   244  func CopyUint8Out(cc marshal.CopyContext, addr hostarch.Addr, src uint8) (int, error) {
   245  	srcP := Uint8(src)
   246  	return srcP.CopyOut(cc, addr)
   247  }
   248  
   249  // 16-bit integers
   250  
   251  // CopyInt16In is a convenient wrapper for copying in an int16 from the task's
   252  // memory.
   253  func CopyInt16In(cc marshal.CopyContext, addr hostarch.Addr, dst *int16) (int, error) {
   254  	var buf Int16
   255  	n, err := buf.CopyIn(cc, addr)
   256  	if err != nil {
   257  		return n, err
   258  	}
   259  	*dst = int16(buf)
   260  	return n, nil
   261  }
   262  
   263  // CopyInt16Out is a convenient wrapper for copying out an int16 to the task's
   264  // memory.
   265  func CopyInt16Out(cc marshal.CopyContext, addr hostarch.Addr, src int16) (int, error) {
   266  	srcP := Int16(src)
   267  	return srcP.CopyOut(cc, addr)
   268  }
   269  
   270  // CopyUint16In is a convenient wrapper for copying in a uint16 from the task's
   271  // memory.
   272  func CopyUint16In(cc marshal.CopyContext, addr hostarch.Addr, dst *uint16) (int, error) {
   273  	var buf Uint16
   274  	n, err := buf.CopyIn(cc, addr)
   275  	if err != nil {
   276  		return n, err
   277  	}
   278  	*dst = uint16(buf)
   279  	return n, nil
   280  }
   281  
   282  // CopyUint16Out is a convenient wrapper for copying out a uint16 to the task's
   283  // memory.
   284  func CopyUint16Out(cc marshal.CopyContext, addr hostarch.Addr, src uint16) (int, error) {
   285  	srcP := Uint16(src)
   286  	return srcP.CopyOut(cc, addr)
   287  }
   288  
   289  // 32-bit integers
   290  
   291  // CopyInt32In is a convenient wrapper for copying in an int32 from the task's
   292  // memory.
   293  func CopyInt32In(cc marshal.CopyContext, addr hostarch.Addr, dst *int32) (int, error) {
   294  	var buf Int32
   295  	n, err := buf.CopyIn(cc, addr)
   296  	if err != nil {
   297  		return n, err
   298  	}
   299  	*dst = int32(buf)
   300  	return n, nil
   301  }
   302  
   303  // CopyInt32Out is a convenient wrapper for copying out an int32 to the task's
   304  // memory.
   305  func CopyInt32Out(cc marshal.CopyContext, addr hostarch.Addr, src int32) (int, error) {
   306  	srcP := Int32(src)
   307  	return srcP.CopyOut(cc, addr)
   308  }
   309  
   310  // CopyUint32In is a convenient wrapper for copying in a uint32 from the task's
   311  // memory.
   312  func CopyUint32In(cc marshal.CopyContext, addr hostarch.Addr, dst *uint32) (int, error) {
   313  	var buf Uint32
   314  	n, err := buf.CopyIn(cc, addr)
   315  	if err != nil {
   316  		return n, err
   317  	}
   318  	*dst = uint32(buf)
   319  	return n, nil
   320  }
   321  
   322  // CopyUint32Out is a convenient wrapper for copying out a uint32 to the task's
   323  // memory.
   324  func CopyUint32Out(cc marshal.CopyContext, addr hostarch.Addr, src uint32) (int, error) {
   325  	srcP := Uint32(src)
   326  	return srcP.CopyOut(cc, addr)
   327  }
   328  
   329  // 64-bit integers
   330  
   331  // CopyInt64In is a convenient wrapper for copying in an int64 from the task's
   332  // memory.
   333  func CopyInt64In(cc marshal.CopyContext, addr hostarch.Addr, dst *int64) (int, error) {
   334  	var buf Int64
   335  	n, err := buf.CopyIn(cc, addr)
   336  	if err != nil {
   337  		return n, err
   338  	}
   339  	*dst = int64(buf)
   340  	return n, nil
   341  }
   342  
   343  // CopyInt64Out is a convenient wrapper for copying out an int64 to the task's
   344  // memory.
   345  func CopyInt64Out(cc marshal.CopyContext, addr hostarch.Addr, src int64) (int, error) {
   346  	srcP := Int64(src)
   347  	return srcP.CopyOut(cc, addr)
   348  }
   349  
   350  // CopyUint64In is a convenient wrapper for copying in a uint64 from the task's
   351  // memory.
   352  func CopyUint64In(cc marshal.CopyContext, addr hostarch.Addr, dst *uint64) (int, error) {
   353  	var buf Uint64
   354  	n, err := buf.CopyIn(cc, addr)
   355  	if err != nil {
   356  		return n, err
   357  	}
   358  	*dst = uint64(buf)
   359  	return n, nil
   360  }
   361  
   362  // CopyUint64Out is a convenient wrapper for copying out a uint64 to the task's
   363  // memory.
   364  func CopyUint64Out(cc marshal.CopyContext, addr hostarch.Addr, src uint64) (int, error) {
   365  	srcP := Uint64(src)
   366  	return srcP.CopyOut(cc, addr)
   367  }
   368  
   369  // CopyByteSliceIn is a convenient wrapper for copying in a []byte from the
   370  // task's memory.
   371  func CopyByteSliceIn(cc marshal.CopyContext, addr hostarch.Addr, dst *[]byte) (int, error) {
   372  	var buf ByteSlice
   373  	n, err := buf.CopyIn(cc, addr)
   374  	if err != nil {
   375  		return n, err
   376  	}
   377  	*dst = []byte(buf)
   378  	return n, nil
   379  }
   380  
   381  // CopyByteSliceOut is a convenient wrapper for copying out a []byte to the
   382  // task's memory.
   383  func CopyByteSliceOut(cc marshal.CopyContext, addr hostarch.Addr, src []byte) (int, error) {
   384  	srcP := ByteSlice(src)
   385  	return srcP.CopyOut(cc, addr)
   386  }
   387  
   388  // CopyStringIn is a convenient wrapper for copying in a string from the
   389  // task's memory.
   390  func CopyStringIn(cc marshal.CopyContext, addr hostarch.Addr, dst *string) (int, error) {
   391  	var buf ByteSlice
   392  	n, err := buf.CopyIn(cc, addr)
   393  	if err != nil {
   394  		return n, err
   395  	}
   396  	*dst = string(buf)
   397  	return n, nil
   398  }
   399  
   400  // CopyStringOut is a convenient wrapper for copying out a string to the task's
   401  // memory.
   402  func CopyStringOut(cc marshal.CopyContext, addr hostarch.Addr, src string) (int, error) {
   403  	srcP := ByteSlice(src)
   404  	return srcP.CopyOut(cc, addr)
   405  }